diff options
-rw-r--r-- | AUTHORS.html | 676 | ||||
-rw-r--r-- | AUTHORS.txt | 33 | ||||
-rw-r--r-- | GPL-3.0.txt | 674 | ||||
-rw-r--r-- | INSTALL.html | 649 | ||||
-rw-r--r-- | INSTALL.txt | 72 | ||||
-rw-r--r-- | LICENSE.html | 1016 | ||||
-rw-r--r-- | LICENSE.txt | 480 | ||||
-rw-r--r-- | MANUAL.html | 1789 | ||||
-rw-r--r-- | MANUAL.txt | 796 | ||||
-rw-r--r-- | Makefile.in | 99 | ||||
-rw-r--r-- | NEWS.html | 1308 | ||||
-rw-r--r-- | NEWS.txt | 407 | ||||
-rw-r--r-- | README.html | 636 | ||||
-rw-r--r-- | README.txt | 81 | ||||
-rw-r--r-- | args.c | 189 | ||||
-rw-r--r-- | ccache.1 | 1365 | ||||
-rw-r--r-- | ccache.c | 2190 | ||||
-rw-r--r-- | ccache.h | 248 | ||||
-rw-r--r-- | cleanup.c | 262 | ||||
-rw-r--r-- | compopt.c | 158 | ||||
-rw-r--r-- | compopt.h | 13 | ||||
-rw-r--r-- | config.h.in | 229 | ||||
-rwxr-xr-x | configure | 6881 | ||||
-rw-r--r-- | counters.c | 71 | ||||
-rw-r--r-- | counters.h | 32 | ||||
-rw-r--r-- | execute.c | 310 | ||||
-rw-r--r-- | exitfn.c | 94 | ||||
-rw-r--r-- | getopt_long.c | 197 | ||||
-rw-r--r-- | getopt_long.h | 30 | ||||
-rw-r--r-- | hash.c | 131 | ||||
-rw-r--r-- | hashtable.c | 303 | ||||
-rw-r--r-- | hashtable.h | 230 | ||||
-rw-r--r-- | hashtable_itr.c | 188 | ||||
-rw-r--r-- | hashtable_itr.h | 122 | ||||
-rw-r--r-- | hashtable_private.h | 85 | ||||
-rw-r--r-- | hashutil.c | 296 | ||||
-rw-r--r-- | hashutil.h | 31 | ||||
-rwxr-xr-x | install-sh | 238 | ||||
-rw-r--r-- | language.c | 155 | ||||
-rw-r--r-- | language.h | 10 | ||||
-rw-r--r-- | lockfile.c | 212 | ||||
-rw-r--r-- | main.c | 28 | ||||
-rw-r--r-- | manifest.c | 671 | ||||
-rw-r--r-- | manifest.h | 11 | ||||
-rw-r--r-- | mdfour.c | 200 | ||||
-rw-r--r-- | mdfour.h | 19 | ||||
-rw-r--r-- | murmurhashneutral2.c | 50 | ||||
-rw-r--r-- | murmurhashneutral2.h | 6 | ||||
-rw-r--r-- | packaging/ccache.changes | 192 | ||||
-rw-r--r-- | packaging/ccache.spec | 59 | ||||
-rw-r--r-- | snprintf.c | 2114 | ||||
-rw-r--r-- | stats.c | 440 | ||||
-rw-r--r-- | system.h | 82 | ||||
-rwxr-xr-x | test.sh | 1835 | ||||
-rw-r--r-- | test/framework.c | 289 | ||||
-rw-r--r-- | test/framework.h | 146 | ||||
-rw-r--r-- | test/main.c | 90 | ||||
-rw-r--r-- | test/suites.h | 9 | ||||
-rw-r--r-- | test/test_args.c | 147 | ||||
-rw-r--r-- | test/test_argument_processing.c | 237 | ||||
-rw-r--r-- | test/test_compopt.c | 97 | ||||
-rw-r--r-- | test/test_counters.c | 62 | ||||
-rw-r--r-- | test/test_hash.c | 59 | ||||
-rw-r--r-- | test/test_hashutil.c | 102 | ||||
-rw-r--r-- | test/test_lockfile.c | 81 | ||||
-rw-r--r-- | test/test_stats.c | 53 | ||||
-rw-r--r-- | test/test_util.c | 44 | ||||
-rw-r--r-- | test/util.c | 46 | ||||
-rw-r--r-- | test/util.h | 8 | ||||
-rw-r--r-- | unify.c | 253 | ||||
-rw-r--r-- | util.c | 1210 | ||||
-rw-r--r-- | version.c | 1 | ||||
-rw-r--r-- | zlib/adler32.c | 149 | ||||
-rw-r--r-- | zlib/compress.c | 79 | ||||
-rw-r--r-- | zlib/crc32.c | 423 | ||||
-rw-r--r-- | zlib/crc32.h | 441 | ||||
-rw-r--r-- | zlib/deflate.c | 1736 | ||||
-rw-r--r-- | zlib/deflate.h | 331 | ||||
-rw-r--r-- | zlib/gzio.c | 1026 | ||||
-rw-r--r-- | zlib/inffast.c | 318 | ||||
-rw-r--r-- | zlib/inffast.h | 11 | ||||
-rw-r--r-- | zlib/inffixed.h | 94 | ||||
-rw-r--r-- | zlib/inflate.c | 1368 | ||||
-rw-r--r-- | zlib/inflate.h | 115 | ||||
-rw-r--r-- | zlib/inftrees.c | 329 | ||||
-rw-r--r-- | zlib/inftrees.h | 55 | ||||
-rw-r--r-- | zlib/trees.c | 1219 | ||||
-rw-r--r-- | zlib/trees.h | 128 | ||||
-rw-r--r-- | zlib/zconf.h | 332 | ||||
-rw-r--r-- | zlib/zlib.h | 1357 | ||||
-rw-r--r-- | zlib/zutil.c | 318 | ||||
-rw-r--r-- | zlib/zutil.h | 269 |
92 files changed, 41725 insertions, 0 deletions
diff --git a/AUTHORS.html b/AUTHORS.html new file mode 100644 index 0000000..11cf16b --- /dev/null +++ b/AUTHORS.html @@ -0,0 +1,676 @@ +<!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.3" />
+<title>ccache authors</title>
+<style type="text/css">
+/* Sans-serif font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+div#toctitle,
+span#author, span#revnumber, span#revdate, span#revremark,
+div#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+/* Serif font. */
+div.sectionbody {
+ font-family: Georgia,"Times New Roman",Times,serif;
+}
+
+/* Monospace font. */
+tt {
+ font-size: inherit;
+}
+
+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;
+}
+
+tt {
+ font-size: inherit;
+ color: navy;
+}
+
+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;
+}
+
+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; }
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+span#email {
+}
+span#revnumber, span#revdate, span#revremark {
+}
+
+div#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.tableblock, 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: #777777;
+}
+
+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; }
+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;
+}
+
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+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;
+}
+
+
+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 {
+ div#footer-badges { display: none; }
+}
+
+div#toc {
+ margin-bottom: 2.5em;
+}
+
+div#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+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;
+}
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
+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]([2-'+(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");
+ 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 () {
+ var cont = document.getElementById("content");
+ var noteholder = document.getElementById("footnotes");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ // 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];
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ 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>]";
+ }
+ }
+ }
+}
+
+}
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache authors</h1>
+<span id="revnumber">version 3.1.6</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>
+Andrea Bittau <<a href="mailto:a.bittau@cs.ucl.ac.uk">a.bittau@cs.ucl.ac.uk</a>>
+</p>
+</li>
+<li>
+<p>
+Andrew Tridgell <<a href="mailto:tridge@samba.org">tridge@samba.org</a>>
+</p>
+</li>
+<li>
+<p>
+Bernhard Bauer <<a href="mailto:bauerb@google.com">bauerb@google.com</a>>
+</p>
+</li>
+<li>
+<p>
+Björn Jacke <<a href="mailto:bj@sernet.de">bj@sernet.de</a>>
+</p>
+</li>
+<li>
+<p>
+Bo Rydberg <<a href="mailto:bolry@hotmail.com">bolry@hotmail.com</a>>
+</p>
+</li>
+<li>
+<p>
+Clemens Rabe <<a href="mailto:crabe@gmx.de">crabe@gmx.de</a>>
+</p>
+</li>
+<li>
+<p>
+Francois Marier <<a href="mailto:francois@debian.org">francois@debian.org</a>>
+</p>
+</li>
+<li>
+<p>
+Joel Rosdahl <<a href="mailto:joel@rosdahl.net">joel@rosdahl.net</a>>
+</p>
+</li>
+<li>
+<p>
+John Coiner <<a href="mailto:john.coiner@amd.com">john.coiner@amd.com</a>>
+</p>
+</li>
+<li>
+<p>
+Karl Chen <<a href="mailto:quarl@cs.berkeley.edu">quarl@cs.berkeley.edu</a>>
+</p>
+</li>
+<li>
+<p>
+Kovarththanan Rajaratnam <<a href="mailto:kovarththanan.rajaratnam@gmail.com">kovarththanan.rajaratnam@gmail.com</a>>
+</p>
+</li>
+<li>
+<p>
+Lars Gustäbel <<a href="mailto:lars@gustaebel.de">lars@gustaebel.de</a>>
+</p>
+</li>
+<li>
+<p>
+Martin Pool <<a href="mailto:mbp@sourcefrog.net">mbp@sourcefrog.net</a>>
+</p>
+</li>
+<li>
+<p>
+Owen Mann <<a href="mailto:owen@mann.org">owen@mann.org</a>>
+</p>
+</li>
+<li>
+<p>
+Paul Griffith <<a href="mailto:paulg@cse.yorku.ca">paulg@cse.yorku.ca</a>>
+</p>
+</li>
+<li>
+<p>
+Ramiro Polla <<a href="mailto:ramiro.polla@gmail.com">ramiro.polla@gmail.com</a>>
+</p>
+</li>
+<li>
+<p>
+Robin H. Johnson <<a href="mailto:robbat2@gentoo.org">robbat2@gentoo.org</a>>
+</p>
+</li>
+<li>
+<p>
+RW <<a href="mailto:fbsd06@mlists.homeunix.com">fbsd06@mlists.homeunix.com</a>>
+</p>
+</li>
+<li>
+<p>
+Tim Potter <<a href="mailto:tpot@samba.org">tpot@samba.org</a>>
+</p>
+</li>
+<li>
+<p>
+Tor Arne Vestbø <<a href="mailto:torarnv@gmail.com">torarnv@gmail.com</a>>
+</p>
+</li>
+<li>
+<p>
+Ville Skyttä <<a href="mailto:ville.skytta@iki.fi">ville.skytta@iki.fi</a>>
+</p>
+</li>
+<li>
+<p>
+William S Fulton <<a href="mailto:wsf@fultondesigns.co.uk">wsf@fultondesigns.co.uk</a>>
+</p>
+</li>
+<li>
+<p>
+Wilson Snyder <<a href="mailto:wsnyder@wsnyder.org">wsnyder@wsnyder.org</a>>
+</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.1.6<br />
+Last updated 2011-08-21 16:32:08 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/AUTHORS.txt b/AUTHORS.txt new file mode 100644 index 0000000..db7a4b0 --- /dev/null +++ b/AUTHORS.txt @@ -0,0 +1,33 @@ +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: + +* Andrea Bittau <a.bittau@cs.ucl.ac.uk> +* Andrew Tridgell <tridge@samba.org> +* Bernhard Bauer <bauerb@google.com> +* Björn Jacke <bj@sernet.de> +* Bo Rydberg <bolry@hotmail.com> +* Clemens Rabe <crabe@gmx.de> +* Francois Marier <francois@debian.org> +* Joel Rosdahl <joel@rosdahl.net> +* John Coiner <john.coiner@amd.com> +* Karl Chen <quarl@cs.berkeley.edu> +* Kovarththanan Rajaratnam <kovarththanan.rajaratnam@gmail.com> +* Lars Gustäbel <lars@gustaebel.de> +* Martin Pool <mbp@sourcefrog.net> +* Owen Mann <owen@mann.org> +* Paul Griffith <paulg@cse.yorku.ca> +* Ramiro Polla <ramiro.polla@gmail.com> +* Robin H. Johnson <robbat2@gentoo.org> +* RW <fbsd06@mlists.homeunix.com> +* Tim Potter <tpot@samba.org> +* Tor Arne Vestbø <torarnv@gmail.com> +* Ville Skyttä <ville.skytta@iki.fi> +* William S Fulton <wsf@fultondesigns.co.uk> +* Wilson Snyder <wsnyder@wsnyder.org> + +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/INSTALL.html b/INSTALL.html new file mode 100644 index 0000000..840bf4d --- /dev/null +++ b/INSTALL.html @@ -0,0 +1,649 @@ +<!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.3" />
+<title>ccache installation</title>
+<style type="text/css">
+/* Sans-serif font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+div#toctitle,
+span#author, span#revnumber, span#revdate, span#revremark,
+div#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+/* Serif font. */
+div.sectionbody {
+ font-family: Georgia,"Times New Roman",Times,serif;
+}
+
+/* Monospace font. */
+tt {
+ font-size: inherit;
+}
+
+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;
+}
+
+tt {
+ font-size: inherit;
+ color: navy;
+}
+
+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;
+}
+
+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; }
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+span#email {
+}
+span#revnumber, span#revdate, span#revremark {
+}
+
+div#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.tableblock, 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: #777777;
+}
+
+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; }
+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;
+}
+
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+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;
+}
+
+
+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 {
+ div#footer-badges { display: none; }
+}
+
+div#toc {
+ margin-bottom: 2.5em;
+}
+
+div#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+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;
+}
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
+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]([2-'+(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");
+ 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 () {
+ var cont = document.getElementById("content");
+ var noteholder = document.getElementById("footnotes");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ // 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];
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ 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>]";
+ }
+ }
+ }
+}
+
+}
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache installation</h1>
+<span id="revnumber">version 3.1.6</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="_building_code_from_a_release_archive">Building code from a release archive</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_prerequisites">Prerequisites</h3>
+<div class="paragraph"><p>To build ccache, you need:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+A C compiler (for instance GCC)
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>It is also recommended that you have:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+zlib <a href="http://www.zlib.net">http://www.zlib.net</a> (if you don’t have zlib installed, ccache will
+ use a bundled copy)
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_installation">Installation</h3>
+<div class="paragraph"><p>To compile and install ccache, run these commands:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><tt>./configure
+make
+make install</tt></pre>
+</div></div>
+<div class="paragraph"><p>You may set the installation directory and other parameters by options to
+“./configure”. To see them, run “./configure --help”.</p></div>
+<div class="paragraph"><p>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.</p></div>
+<div class="paragraph"><p>To install for usage by the first method just copy ccache to somewhere in your
+path.</p></div>
+<div class="paragraph"><p>To install for the second method, do something like this:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><tt>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++</tt></pre>
+</div></div>
+<div class="paragraph"><p>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.</p></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content">Do not use a hard link, use a symbolic link. A hard link will cause
+“interesting” problems.</td>
+</tr></table>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_building_code_from_the_source_code_repository">Building code from the source code repository</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>In addition to the prerequisites mentioned above, you also need:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+AsciiDoc (<a href="http://www.methods.co.nz/asciidoc/">http://www.methods.co.nz/asciidoc/</a>) to build the documentation.
+</p>
+</li>
+<li>
+<p>
+Autoconf (<a href="http://www.gnu.org/software/autoconf/">http://www.gnu.org/software/autoconf/</a>)
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>To debug and run the performance test suite you’ll also need:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Perl (<a href="http://www.perl.org/">http://www.perl.org/</a>)
+</p>
+</li>
+<li>
+<p>
+Python (<a href="http://www.python.org/">http://www.python.org/</a>)
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Run "./autogen.sh" and then follow the steps mentioned under "Installation"
+above.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Version 3.1.6<br />
+Last updated 2010-04-28 20:58:43 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 0000000..1968d2b --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,72 @@ +ccache installation +=================== + + +Building code from a release archive +------------------------------------ + +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. + + +Building code from the source code repository +--------------------------------------------- + +In addition to the prerequisites mentioned above, you also need: + +- AsciiDoc (http://www.methods.co.nz/asciidoc/) to build the documentation. +- Autoconf (http://www.gnu.org/software/autoconf/) + +To debug and run the performance test suite you'll also need: + +- Perl (http://www.perl.org/) +- Python (http://www.python.org/) + +Run "./autogen.sh" and then follow the steps mentioned under "Installation" +above. diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000..0c5721e --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,1016 @@ +<!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.3" />
+<title>ccache copyright and license</title>
+<style type="text/css">
+/* Sans-serif font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+div#toctitle,
+span#author, span#revnumber, span#revdate, span#revremark,
+div#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+/* Serif font. */
+div.sectionbody {
+ font-family: Georgia,"Times New Roman",Times,serif;
+}
+
+/* Monospace font. */
+tt {
+ font-size: inherit;
+}
+
+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;
+}
+
+tt {
+ font-size: inherit;
+ color: navy;
+}
+
+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;
+}
+
+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; }
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+span#email {
+}
+span#revnumber, span#revdate, span#revremark {
+}
+
+div#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.tableblock, 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: #777777;
+}
+
+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; }
+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;
+}
+
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+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;
+}
+
+
+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 {
+ div#footer-badges { display: none; }
+}
+
+div#toc {
+ margin-bottom: 2.5em;
+}
+
+div#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+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;
+}
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
+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]([2-'+(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");
+ 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 () {
+ var cont = document.getElementById("content");
+ var noteholder = document.getElementById("footnotes");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ // 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];
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ 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>]";
+ }
+ }
+ }
+}
+
+}
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache copyright and license</h1>
+<span id="revnumber">version 3.1.6</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><tt> 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</tt></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="http://ccache.samba.org/authors.html">http://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><tt> Copyright (C) 2002-2007 Andrew Tridgell
+ Copyright (C) 2009-2011 Joel Rosdahl</tt></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 “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.</p></div>
+<div class="sect2">
+<h3 id="_getopt_long_hc">getopt_long.[hc]</h3>
+<div class="paragraph"><p>This implementation of <tt>getopt_long()</tt> 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><tt> 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.</tt></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><tt> 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.</tt></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’s
+<tt>configure.in</tt> with the following license:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt> 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.</tt></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 <tt>snprintf()</tt> 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><tt> 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.</tt></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.3 from <a href="http://www.zlib.net">http://www.zlib.net</a> with the
+following license:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt> Copyright (C) 1995-2005 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://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).</tt></pre>
+</div></div>
+</div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Version 3.1.6<br />
+Last updated 2011-08-21 16:32:08 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..7d165ce --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,480 @@ +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 http://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-2011 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.3 from <http://www.zlib.net> with the +following license: + +------------------------------------------------------------------------------- + Copyright (C) 1995-2005 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://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +------------------------------------------------------------------------------- diff --git a/MANUAL.html b/MANUAL.html new file mode 100644 index 0000000..97398e7 --- /dev/null +++ b/MANUAL.html @@ -0,0 +1,1789 @@ +<!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.3" />
+<title>CCACHE(1)</title>
+<style type="text/css">
+/* Sans-serif font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+div#toctitle,
+span#author, span#revnumber, span#revdate, span#revremark,
+div#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+/* Serif font. */
+div.sectionbody {
+ font-family: Georgia,"Times New Roman",Times,serif;
+}
+
+/* Monospace font. */
+tt {
+ font-size: inherit;
+}
+
+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;
+}
+
+tt {
+ font-size: inherit;
+ color: navy;
+}
+
+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;
+}
+
+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; }
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+span#email {
+}
+span#revnumber, span#revdate, span#revremark {
+}
+
+div#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.tableblock, 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: #777777;
+}
+
+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; }
+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;
+}
+
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+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;
+}
+
+
+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 {
+ div#footer-badges { display: none; }
+}
+
+div#toc {
+ margin-bottom: 2.5em;
+}
+
+div#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+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;
+}
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
+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]([2-'+(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");
+ 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 () {
+ var cont = document.getElementById("content");
+ var noteholder = document.getElementById("footnotes");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ // 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];
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ 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>]";
+ }
+ }
+ }
+}
+
+}
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>CCACHE(1)</h1>
+<span id="revnumber">version 3.1.6</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="#_bugs">BUGS</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><tt>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++</tt></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 <tt>/usr/bin</tt>). After
+installing you may wish to run “which gcc” 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’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
+“interesting” 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 “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.</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, it’s not needed 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.
+</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. The value is stored
+ inside the cache directory and applies to all future compilations. Due to
+ the way the value is stored the actual value used is always rounded down to
+ the nearest multiple of 16.
+</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. You can specify a
+ value in gigabytes, megabytes or kilobytes by appending a G, M or K to the
+ value. The default is gigabytes. The actual value stored is rounded down to
+ the nearest multiple of 16 kilobytes.
+</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 configured limits).
+</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="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’t, since the option has another meaning for your
+compiler than what ccache thinks.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_environment_variables">Environment variables</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ccache uses a number of environment variables to control operation. In most
+cases you won’t need any of these as the defaults will be fine.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<strong>CCACHE_BASEDIR</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_BASEDIR</strong> to an absolute path to
+ a directory, ccache rewrites absolute paths into relative paths before
+ computing the hash that identifies the compilation, but only for paths
+ under the specified directory. See the discussion under
+ <a href="#_compiling_in_different_directories">COMPILING IN DIFFERENT DIRECTORIES</a>.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_CC</strong>
+</dt>
+<dd>
+<p>
+ You can optionally set <strong>CCACHE_CC</strong> to force the name of the compiler to
+ use. If you don’t do this then ccache works it out from the command line.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_COMPILERCHECK</strong>
+</dt>
+<dd>
+<p>
+ 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. The <strong>CCACHE_COMPILERCHECK</strong> environment variable 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’s mtime and size, which is fast. This is the default.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>none</strong>
+</dt>
+<dd>
+<p>
+ 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 <strong>none</strong> setting if
+ you know what you are doing.
+</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 “%compiler%” 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="ulist"><ul>
+<li>
+<p>
+<tt>%compiler% -v</tt>
+</p>
+</li>
+<li>
+<p>
+<tt>%compiler% -dumpmachine; %compiler% -dumpversion</tt>
+</p>
+</li>
+</ul></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’t the real
+compiler but another compiler wrapper — 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’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 <strong>mtime</strong> method in combination with
+<strong>CCACHE_PREFIX</strong> 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>CCACHE_COMPRESS</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_COMPRESS</strong> then 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.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_CPP2</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_CPP2</strong> then ccache will not use
+ the optimisation of avoiding the second call to the preprocessor by
+ compiling the preprocessed output that was used for finding the hash in the
+ case of a cache miss. This is primarily a debugging option, although it is
+ possible that some unusual compilers will have problems with the
+ intermediate filename extensions used in this optimisation, in which case
+ this option could allow ccache to be used anyway.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_DETECT_SHEBANG</strong>
+</dt>
+<dd>
+<p>
+ The <strong>CCACHE_DETECT_SHEBANG</strong> environment variable only has meaning on
+ Windows. It instructs ccache to open the executable file to detect the
+ <strong>#!/bin/sh</strong> string, in which case ccache will search for <strong>sh.exe</strong> in
+ <strong>PATH</strong> and use that to launch the executable.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_DIR</strong>
+</dt>
+<dd>
+<p>
+ The <strong>CCACHE_DIR</strong> environment variable specifies where ccache will keep its
+ cached compiler output. The default is <strong>$HOME/.ccache</strong>.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_DISABLE</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_DISABLE</strong> then ccache will just
+ call the real compiler, bypassing the cache completely.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_EXTENSION</strong>
+</dt>
+<dd>
+<p>
+ ccache tries to automatically determine the extension to use for
+ intermediate preprocessor files based on the type of file being compiled.
+ Unfortunately this sometimes doesn’t work, for example when using the
+ “aCC” compiler on HP-UX. On systems like this you can use the
+ <strong>CCACHE_EXTENSION</strong> option to override the default. On HP-UX set this
+ environment variable to <strong>i</strong> if you use the “aCC” compiler.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_EXTRAFILES</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_EXTRAFILES</strong> to a list of paths
+ then ccache will include the contents of those files when calculating the
+ hash sum. The list separator is semicolon in Windows systems and colon on
+ other systems.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_HARDLINK</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_HARDLINK</strong> then 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 set the <strong>CCACHE_COMPRESS</strong> variable if you
+ want to use hard links.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_HASHDIR</strong>
+</dt>
+<dd>
+<p>
+ This tells ccache to hash the current working directory when calculating
+ the hash that is used to distinguish two compilations. This prevents a
+ problem with the storage of the current working directory in the debug info
+ of a object file, which can lead ccache to give a cached object file that
+ has the working directory in the debug info set incorrectly. This option is
+ off by default as the incorrect setting of this debug info rarely causes
+ problems. If you strike problems with GDB not using the correct directory
+ then enable this option.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_LOGFILE</strong>
+</dt>
+<dd>
+<p>
+ If you set the <strong>CCACHE_LOGFILE</strong> environment variable then 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>CCACHE_NLEVELS</strong>
+</dt>
+<dd>
+<p>
+ The environment variable <strong>CCACHE_NLEVELS</strong> allows you to choose the number
+ of levels of hash in the cache directory. The default is 2. The minimum is
+ 1 and the maximum is 8.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_NODIRECT</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_NODIRECT</strong> then ccache will not
+ use the direct mode.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_NOSTATS</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_NOSTATS</strong> then ccache will not
+ update the statistics files on each compilation.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_PATH</strong>
+</dt>
+<dd>
+<p>
+ You can optionally set <strong>CCACHE_PATH</strong> to a colon-separated path where ccache
+ will look for the real compilers. If you don’t do this then ccache will
+ look for the first executable matching the compiler name in the normal
+ <strong>PATH</strong> that isn’t a symbolic link to ccache itself.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_PREFIX</strong>
+</dt>
+<dd>
+<p>
+ This option adds a prefix to the command line that ccache runs when
+ invoking the compiler. Also see the section below on using ccache with
+ “distcc”.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_READONLY</strong>
+</dt>
+<dd>
+<p>
+ The <strong>CCACHE_READONLY</strong> environment variable tells ccache to attempt to use
+ existing cached object files, but not to try to add anything new to the
+ cache. If you are using this because your <strong>CCACHE_DIR</strong> is read-only, then
+ you may find that you also need to set <strong>CCACHE_TEMPDIR</strong> as otherwise ccache
+ will fail to create temporary files.
+</p>
+</dd>
+<dt class="hdlist1">
+<strong>CCACHE_RECACHE</strong>
+</dt>
+<dd>
+<p>
+ This forces ccache to not use any cached results, even if it finds them.
+ New results are still cached, but existing cache entries are ignored.
+</p>
+</dd>
+<dt class="hdlist1">
+<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’s possible that you know things that
+ ccache can’t take for granted. The <strong>CCACHE_SLOPPINESS</strong> environment variable
+ 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>include_file_mtime</strong>
+</dt>
+<dd>
+<p>
+ Don’t check the modification time of include files in the direct mode.
+</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>CCACHE_TEMPDIR</strong>
+</dt>
+<dd>
+<p>
+ The <strong>CCACHE_TEMPDIR</strong> environment variable specifies where ccache will put
+ temporary files. The default is <strong>$CCACHE_DIR/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>CCACHE_UMASK</strong>
+</dt>
+<dd>
+<p>
+ This sets 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>CCACHE_UNIFY</strong>
+</dt>
+<dd>
+<p>
+ If you set the environment variable <strong>CCACHE_UNIFY</strong> then 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 using <strong>CCACHE_UNIFY</strong> changes the
+ hash, so cached compilations with <strong>CCACHE_UNIFY</strong> set cannot be used when
+ <strong>CCACHE_UNIFY</strong> is not set and vice versa. The reason the unifier is off by
+ default is that it can give incorrect line number information in compiler
+ warning messages. Also note that enabling the unifier implies turning off
+ the direct mode.
+</p>
+</dd>
+</dl></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 one 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 involves a negligible performance
+slowdown, it significantly increases the number of files that fit in the cache.
+You can turn on compression by setting the <strong>CCACHE_COMPRESS</strong> environment
+variable.</p></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’s size and modification time (or other compiler-specific
+ information specified by <strong>CCACHE_COMPILERCHECK</strong>)
+</p>
+</li>
+<li>
+<p>
+the name of the compiler
+</p>
+</li>
+<li>
+<p>
+the current directory (if <strong>CCACHE_HASHDIR</strong> is set)
+</p>
+</li>
+<li>
+<p>
+contents of files specified by <strong>CCACHE_EXTRAFILES</strong> (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 “manifest” 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>The direct mode will be disabled if any of the following holds:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the environment variable <strong>CCACHE_NODIRECT</strong> is set
+</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 environment variable <strong>CCACHE_UNIFY</strong> is set)
+</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> and
+ <strong>-Wp,-MMD,<em>path</em></strong>
+</p>
+</li>
+<li>
+<p>
+<strong>-Xpreprocessor</strong>
+</p>
+</li>
+</ul></div>
+</li>
+<li>
+<p>
+the string “__TIME__” is present outside comments and string literals 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’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” by setting
+the <strong>CCACHE_BASEDIR</strong> variable 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 <tt>/</tt> as
+the base directory since that will make ccache also rewrite paths to system
+header files, which doesn’t gain anything.)</p></div>
+<div class="paragraph"><p>The drawbacks of using <strong>CCACHE_BASEDIR</strong> 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
+ “cd” 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’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>CCACHE_SLOPPINESS</strong> to <strong>time_macros</strong>. The reason is that ccache
+ can’t tell whether <strong>__TIME__</strong> or <strong>__DATE__</strong> is used when using a
+ precompiled header.
+</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’t use <strong>#include</strong> in the source code to include the 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’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).</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 <strong>CCACHE_DIR</strong> environment variable setting.
+</p>
+</li>
+<li>
+<p>
+Unset the <strong>CCACHE_HARDLINK</strong> environment variable.
+</p>
+</li>
+<li>
+<p>
+Make sure everyone sets the <strong>CCACHE_UMASK</strong> environment variable 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
+ command “find $CCACHE_DIR -type d | xargs chmod g+s” might be useful for
+ this.
+</p>
+</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’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 the developers have <strong>CCACHE_BASEDIR</strong> set
+appropriately, as discussed in the 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’s worth it.
+</p>
+</li>
+<li>
+<p>
+ccache hasn’t been tested very thoroughly on NFS.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>A tip is to set <strong>CCACHE_TEMPDIR</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
+“distcc”) is by using the <strong>CCACHE_PREFIX</strong> option. You just need to set the
+environment variable <strong>CCACHE_PREFIX</strong> to the name of the wrapper (e.g. <strong>distcc</strong>)
+and ccache will prefix the command line with the specified command when running
+the compiler.</p></div>
+<div class="paragraph"><p>Unless you set <strong>CCACHE_COMPILERCHECK</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’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>CCACHE_PREFIX</strong> is not used, ccache will
+needlessly invoke the other wrapper when running the preprocessor.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_bugs">Bugs</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+ccache doesn’t handle the GNU Assembler’s <strong>.incbin</strong> directive correctly. This
+ directive can be embedded in the source code inside an <strong><em>asm</em></strong> statement in
+ order to include a file verbatim in the object file. If the included file is
+ modified, ccache doesn’t pick up the change since the inclusion isn’t done by
+ the preprocessor. A workaround of this problem is to set <strong>CCACHE_EXTRAFILES</strong>
+ to the path of the included file.
+</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>CCACHE_LOGFILE</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 preferrable.</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 “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:
+</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’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>
+ and <strong>Wp,-MMD,<em>path</em></strong>) is used.
+</p>
+</li>
+<li>
+<p>
+This was the first compilation with a new value of <strong>CCACHE_BASEDIR</strong>.
+</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>CCACHE_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’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 “__TIME__” is present in the source code
+ outside comments and string literals. 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’t used
+ in practise, or don’t care if ccache produces objects where <strong>__TIME__</strong> is
+ expanded to something in the past, you can set <strong>CCACHE_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
+ “__DATE__” is present in the source code outside comments and string
+ literals, 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’t used in practise, or don’t care if ccache
+ produces objects where <strong>__DATE__</strong> is expanded to something in the past,
+ you can set <strong>CCACHE_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 “__FILE__” is present in the source code
+ outside comments and string literals, 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’t
+ used in practise, or don’t care if ccache produces objects where
+ <strong>__FILE__</strong> is expanded to the wrong path, you can set <strong>CCACHE_SLOPPINESS</strong>
+ to <strong>file_macro</strong>.
+</p>
+</li>
+</ul></div>
+</li>
+<li>
+<p>
+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 <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 “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.
+</p>
+</li>
+<li>
+<p>
+If “unsupported compiler option” has been incremented, enable debug logging
+ and check which option was rejected.
+</p>
+</li>
+<li>
+<p>
+If “preprocessor error” 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 “can’t use precompiled header” has been incremented, see
+ <a href="#_precompiled_headers">PRECOMPILED HEADERS</a>.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_errors_when_compiling_with_ccache">Errors when compiling with ccache</h3>
+<div class="paragraph"><p>If compilation doesn’t work with ccache, but it works without it, one possible
+reason is that the compiler can’t compile preprocessed output correctly. A
+workaround that may work is to set <strong>CCACHE_CPP2</strong>. This will make cache misses
+slower, though, so it is better to find and fix the root cause.</p></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>CCACHE_PREFIX</strong> command or compiler wrapper. If this happens, you can either
+find out which object file is broken by reading the debug log and then delete
+the bad object file from the cache, or you can simply clear the whole cache
+with <strong>ccache -C</strong> if you don’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’t mean it can’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’s web site: <a href="http://ccache.samba.org">http://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="http://ccache.samba.org/credits.html">http://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.1.6<br />
+Last updated 2011-08-14 21:46:15 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/MANUAL.txt b/MANUAL.txt new file mode 100644 index 0000000..0a67b9f --- /dev/null +++ b/MANUAL.txt @@ -0,0 +1,796 @@ +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 <<_bugs,BUGS>>. 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, it's not needed 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. + +*-F, --max-files*='N':: + + Set the maximum number of files allowed in the cache. The value is stored + inside the cache directory and applies to all future compilations. Due to + the way the value is stored the actual value used is always rounded down to + the nearest multiple of 16. + +*-h, --help*:: + + Print an options summary page. + +*-M, --max-size*='SIZE':: + + Set the maximum size of the files stored in the cache. You can specify a + value in gigabytes, megabytes or kilobytes by appending a G, M or K to the + value. The default is gigabytes. The actual value stored is rounded down to + the nearest multiple of 16 kilobytes. + +*-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 configured limits). + + +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. + +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. + + +Environment variables +--------------------- + +ccache uses a number of environment variables to control operation. In most +cases you won't need any of these as the defaults will be fine. + +*CCACHE_BASEDIR*:: + + If you set the environment variable *CCACHE_BASEDIR* to an absolute path to + a directory, ccache rewrites absolute paths into relative paths before + computing the hash that identifies the compilation, but only for paths + under the specified directory. See the discussion under + <<_compiling_in_different_directories,COMPILING IN DIFFERENT DIRECTORIES>>. + +*CCACHE_CC*:: + + You can optionally set *CCACHE_CC* to force the name of the compiler to + use. If you don't do this then ccache works it out from the command line. + +*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. The *CCACHE_COMPILERCHECK* environment variable 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. +_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 +*CCACHE_PREFIX* if possible. See +<<_using_ccache_with_other_compiler_wrappers,USING CCACHE WITH OTHER COMPILER +WRAPPERS>>. +-- +-- + +*CCACHE_COMPRESS*:: + + If you set the environment variable *CCACHE_COMPRESS* then 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. + +*CCACHE_CPP2*:: + + If you set the environment variable *CCACHE_CPP2* then ccache will not use + the optimisation of avoiding the second call to the preprocessor by + compiling the preprocessed output that was used for finding the hash in the + case of a cache miss. This is primarily a debugging option, although it is + possible that some unusual compilers will have problems with the + intermediate filename extensions used in this optimisation, in which case + this option could allow ccache to be used anyway. + +*CCACHE_DETECT_SHEBANG*:: + + The *CCACHE_DETECT_SHEBANG* environment variable only has meaning on + Windows. It instructs ccache to open the executable file to detect the + *#!/bin/sh* string, in which case ccache will search for *sh.exe* in + *PATH* and use that to launch the executable. + +*CCACHE_DIR*:: + + The *CCACHE_DIR* environment variable specifies where ccache will keep its + cached compiler output. The default is *$HOME/.ccache*. + +*CCACHE_DISABLE*:: + + If you set the environment variable *CCACHE_DISABLE* then ccache will just + call the real compiler, bypassing the cache completely. + +*CCACHE_EXTENSION*:: + + ccache tries to automatically determine the extension to use for + intermediate preprocessor files based on the type of file being compiled. + Unfortunately this sometimes doesn't work, for example when using the + ``aCC'' compiler on HP-UX. On systems like this you can use the + *CCACHE_EXTENSION* option to override the default. On HP-UX set this + environment variable to *i* if you use the ``aCC'' compiler. + +*CCACHE_EXTRAFILES*:: + + If you set the environment variable *CCACHE_EXTRAFILES* to a list of paths + then ccache will include the contents of those files when calculating the + hash sum. The list separator is semicolon in Windows systems and colon on + other systems. + +*CCACHE_HARDLINK*:: + + If you set the environment variable *CCACHE_HARDLINK* then 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 set the *CCACHE_COMPRESS* variable if you + want to use hard links. + +*CCACHE_HASHDIR*:: + + This tells ccache to hash the current working directory when calculating + the hash that is used to distinguish two compilations. This prevents a + problem with the storage of the current working directory in the debug info + of a object file, which can lead ccache to give a cached object file that + has the working directory in the debug info set incorrectly. This option is + off by default as the incorrect setting of this debug info rarely causes + problems. If you strike problems with GDB not using the correct directory + then enable this option. + +*CCACHE_LOGFILE*:: + + If you set the *CCACHE_LOGFILE* environment variable then ccache will write + information on what it is doing to the specified file. This is useful for + tracking down problems. + +*CCACHE_NLEVELS*:: + + The environment variable *CCACHE_NLEVELS* allows you to choose the number + of levels of hash in the cache directory. The default is 2. The minimum is + 1 and the maximum is 8. + +*CCACHE_NODIRECT*:: + + If you set the environment variable *CCACHE_NODIRECT* then ccache will not + use the direct mode. + +*CCACHE_NOSTATS*:: + + If you set the environment variable *CCACHE_NOSTATS* then ccache will not + update the statistics files on each compilation. + +*CCACHE_PATH*:: + + You can optionally set *CCACHE_PATH* to a colon-separated path where ccache + will look for the real compilers. If you don't do this then ccache will + look for the first executable matching the compiler name in the normal + *PATH* that isn't a symbolic link to ccache itself. + +*CCACHE_PREFIX*:: + + This option adds a prefix to the command line that ccache runs when + invoking the compiler. Also see the section below on using ccache with + ``distcc''. + +*CCACHE_READONLY*:: + + The *CCACHE_READONLY* environment variable tells ccache to attempt to use + existing cached object files, but not to try to add anything new to the + cache. If you are using this because your *CCACHE_DIR* is read-only, then + you may find that you also need to set *CCACHE_TEMPDIR* as otherwise ccache + will fail to create temporary files. + +*CCACHE_RECACHE*:: + + This forces ccache to not use any cached results, even if it finds them. + New results are still cached, but existing cache entries are ignored. + +*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. The *CCACHE_SLOPPINESS* environment variable + 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. +*include_file_mtime*:: + Don't check the modification time of include files in the direct mode. +*time_macros*:: + Ignore *\_\_DATE\__* and *\_\_TIME__* being present in the source code. +-- ++ +See the discussion under <<_troubleshooting,TROUBLESHOOTING>> for more +information. + +*CCACHE_TEMPDIR*:: + + The *CCACHE_TEMPDIR* environment variable specifies where ccache will put + temporary files. The default is *$CCACHE_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.) + +*CCACHE_UMASK*:: + + This sets 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. + +*CCACHE_UNIFY*:: + + If you set the environment variable *CCACHE_UNIFY* then 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 using *CCACHE_UNIFY* changes the + hash, so cached compilations with *CCACHE_UNIFY* set cannot be used when + *CCACHE_UNIFY* is not set and vice versa. The reason the unifier is off by + default is that it can give incorrect line number information in compiler + warning messages. Also note that enabling the unifier implies turning off + the direct mode. + + +Cache size management +--------------------- + +By default ccache has a one 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 involves a negligible performance +slowdown, it significantly increases the number of files that fit in the cache. +You can turn on compression by setting the *CCACHE_COMPRESS* environment +variable. + + +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 *CCACHE_COMPILERCHECK*) +* the name of the compiler +* the current directory (if *CCACHE_HASHDIR* is set) +* contents of files specified by *CCACHE_EXTRAFILES* (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. + +The direct mode will be disabled if any of the following holds: + +* the environment variable *CCACHE_NODIRECT* is set +* a modification time of one of the include files is too new (needed to avoid a + race condition) +* the unifier is enabled (the environment variable *CCACHE_UNIFY* is set) +* a compiler option not supported by the direct mode is used: +** a *-Wp,_X_* compiler option other than *-Wp,-MD,_path_* and + *-Wp,-MMD,_path_* +** *-Xpreprocessor* +* the string ``\_\_TIME__'' is present outside comments and string literals 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'' by setting +the *CCACHE_BASEDIR* variable 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 *CCACHE_BASEDIR* 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 *CCACHE_SLOPPINESS* to *time_macros*. The reason is that ccache + can't tell whether *\_\_TIME\__* or *\_\_DATE__* is used when using a + precompiled header. +* 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 +** 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 *CCACHE_DIR* environment variable setting. +* Unset the *CCACHE_HARDLINK* environment variable. +* Make sure everyone sets the *CCACHE_UMASK* environment variable 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 + command ``find $CCACHE_DIR -type d | xargs chmod g+s'' might be useful for + this. + +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 the developers have *CCACHE_BASEDIR* set +appropriately, as discussed in the 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 *CCACHE_TEMPDIR* 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 using the *CCACHE_PREFIX* option. You just need to set the +environment variable *CCACHE_PREFIX* to the name of the wrapper (e.g. *distcc*) +and ccache will prefix the command line with the specified command when running +the compiler. + +Unless you set *CCACHE_COMPILERCHECK* 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 *CCACHE_PREFIX* is not used, ccache will +needlessly invoke the other wrapper when running the preprocessor. + + +Bugs +---- + +* ccache doesn't handle the GNU Assembler's *.incbin* directive correctly. This + directive can be embedded in the source code inside an *__asm__* statement in + order to include a file verbatim in the object file. If the included file is + modified, ccache doesn't pick up the change since the inclusion isn't done by + the preprocessor. A workaround of this problem is to set *CCACHE_EXTRAFILES* + to the path of the included file. + + + +Troubleshooting +--------------- + +General +~~~~~~~ + +A general tip for getting information about what ccache is doing is to enable +debug logging by setting *CCACHE_LOGFILE*. 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 preferrable. + +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_* + and *Wp,-MMD,_path_*) is used. +** This was the first compilation with a new value of *CCACHE_BASEDIR*. +** 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 *CCACHE_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 + outside comments and string literals. 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 *CCACHE_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 outside comments and string + literals, 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 *CCACHE_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 + outside comments and string literals, 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 *CCACHE_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>>. + + +Errors when compiling with ccache +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If compilation doesn't work with ccache, but it works without it, one possible +reason is that the compiler can't compile preprocessed output correctly. A +workaround that may work is to set *CCACHE_CPP2*. This will make cache misses +slower, though, so it is better to find and fix the root cause. + + +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 +*CCACHE_PREFIX* command or compiler wrapper. If this happens, you can either +find out which object file is broken by reading the debug log and then delete +the bad object file from the cache, or you can simply 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: <http://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 +<http://ccache.samba.org/credits.html> for a list of contributors. diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..e3f6e51 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,99 @@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +mandir = @mandir@ +datarootdir = @datarootdir@ +installcmd = @INSTALL@ + +AR = @AR@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @DEFS@ @CPPFLAGS@ -I. -I$(srcdir) +LDFLAGS = @LDFLAGS@ +EXEEXT = @EXEEXT@ +RANLIB = @RANLIB@ + +libs = @LIBS@ -lz + +base_sources = \ + ccache.c mdfour.c hash.c execute.c util.c args.c stats.c version.c \ + cleanup.c snprintf.c unify.c manifest.c hashtable.c hashtable_itr.c \ + murmurhashneutral2.c hashutil.c getopt_long.c exitfn.c lockfile.c \ + counters.c language.c compopt.c +base_objs = $(base_sources:.c=.o) + +ccache_sources = main.c $(base_sources) +ccache_objs = $(ccache_sources:.c=.o) + +zlib_sources = \ + zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.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) *~ +files_to_distclean = Makefile config.h config.log config.status + +.PHONY: all +all: ccache$(EXEEXT) + +ccache$(EXEEXT): $(ccache_objs) @extra_deps@ + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(ccache_objs) $(libs) + +.PHONY: install +install: all + $(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 -f $(files_to_clean) + +zlib/libz.a: $(zlib_objs) + $(AR) cr $@ $(zlib_objs) + $(RANLIB) $@ + +.PHONY: perf +perf: ccache$(EXEEXT) + $(srcdir)/perf.py --ccache ccache$(EXEEXT) $(CC) $(CFLAGS) $(CPPFLAGS) $(srcdir)/ccache.c + +.PHONY: test +test: ccache$(EXEEXT) test/main$(EXEEXT) + test/main$(EXEEXT) + CC='$(CC)' $(srcdir)/test.sh + +test/main$(EXEEXT): $(base_objs) $(test_objs) @extra_deps@ + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(base_objs) $(test_objs) $(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) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +@include_dev_mk@ diff --git a/NEWS.html b/NEWS.html new file mode 100644 index 0000000..0d5a369 --- /dev/null +++ b/NEWS.html @@ -0,0 +1,1308 @@ +<!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.3" />
+<title>ccache news</title>
+<style type="text/css">
+/* Sans-serif font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+div#toctitle,
+span#author, span#revnumber, span#revdate, span#revremark,
+div#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+/* Serif font. */
+div.sectionbody {
+ font-family: Georgia,"Times New Roman",Times,serif;
+}
+
+/* Monospace font. */
+tt {
+ font-size: inherit;
+}
+
+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;
+}
+
+tt {
+ font-size: inherit;
+ color: navy;
+}
+
+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;
+}
+
+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; }
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+span#email {
+}
+span#revnumber, span#revdate, span#revremark {
+}
+
+div#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.tableblock, 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: #777777;
+}
+
+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; }
+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;
+}
+
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+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;
+}
+
+
+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 {
+ div#footer-badges { display: none; }
+}
+
+div#toc {
+ margin-bottom: 2.5em;
+}
+
+div#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+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;
+}
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
+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]([2-'+(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");
+ 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 () {
+ var cont = document.getElementById("content");
+ var noteholder = document.getElementById("footnotes");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ // 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];
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ 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>]";
+ }
+ }
+ }
+}
+
+}
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache news</h1>
+<span id="revnumber">version 3.1.6</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_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">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Rewrite argument to --sysroot if CCACHE_BASEDIR is used.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Don’t crash if getcwd() fails.
+</p>
+</li>
+<li>
+<p>
+Fixed alignment of "called for preprocessing" 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_2">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added a new statistics counter named “called for preprocessing”.
+</p>
+</li>
+<li>
+<p>
+The original command line is now logged to the file specified with
+ <tt>CCACHE_LOGFILE</tt>.
+</p>
+</li>
+<li>
+<p>
+Improved error logging when system calls fail.
+</p>
+</li>
+<li>
+<p>
+Added support for rewriting absolute paths in <tt>-F</tt>/<tt>-iframework</tt> GCC
+ options.
+</p>
+</li>
+<li>
+<p>
+Improved order of statistics counters in <tt>ccache -s</tt> output.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_2">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The <tt>-MF</tt>/<tt>-MT</tt>/<tt>-MQ</tt> 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 <tt>-MT</tt>/<tt>-MQ</tt> options with
+ concatenated arguments.
+</p>
+</li>
+<li>
+<p>
+Fixed a minor memory leak.
+</p>
+</li>
+<li>
+<p>
+Systems that lack (and don’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_3">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Made a work-around for a bug in gzputc() in zlib 1.2.5.
+</p>
+</li>
+<li>
+<p>
+Corrupt manifest files are now removed so that they won’t block direct
+ mode hits.
+</p>
+</li>
+<li>
+<p>
+ccache now copes with file systems that don’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_4">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">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_5">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Bail out on too hard compiler options <tt>-fdump-*</tt>.
+</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_2">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 “too new header file” 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_6">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
+ <tt>describe</tt> command doesn’t understand <tt>--dirty</tt>.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_3">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_3">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+Added support for hashing the output of a custom command (e.g.
+ <tt>%compiler% --version</tt>) 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.
+</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 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.
+</p>
+</li>
+<li>
+<p>
+Added <tt>.cp</tt> and <tt>.CP</tt> as known C++ suffixes.
+</p>
+</li>
+<li>
+<p>
+Improved logging.
+</p>
+</li>
+<li>
+<p>
+Added <tt>-install_name</tt> 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_7">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 <tt>--ccache-skip</tt> is used.
+</p>
+</li>
+<li>
+<p>
+Made <tt>--ccache-skip</tt> work for all options.
+</p>
+</li>
+<li>
+<p>
+EINTR is now handled correctly.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_other_4">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 <tt>--nostats</tt> 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 <tt>configure-dev</tt>; dev mode is now given by <tt>dev.mk.in</tt>
+ presence.
+</p>
+</li>
+<li>
+<p>
+Improved documentation on how to combine ccache with other compiler
+ wrappers (like <tt>distcc</tt>).
+</p>
+</li>
+<li>
+<p>
+New <tt>LICENSE.txt</tt> file with licensing and copyright details about bundled
+ source code.
+</p>
+</li>
+<li>
+<p>
+New <tt>AUTHORS.txt</tt> file with a list of ccache contributors.
+</p>
+</li>
+<li>
+<p>
+New <tt>HACKING.txt</tt> 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_8">Bug fixes</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+The statistics counter “called for link” 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’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 <tt>ccache
+ --clear</tt> 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_4">New features and improvements</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+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 <tt>CCACHE_NODIRECT</tt>.
+</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 <tt>-g</tt> and
+ when using absolute include directory paths. This is done by setting the
+ <tt>CCACHE_BASEDIR</tt> 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 <tt>CCACHE_COMPRESS</tt> to enable object
+ file compression. Note that you can’t use compression in combination with
+ the hard link feature.
+</p>
+</li>
+<li>
+<p>
+A <tt>CCACHE_COMPILERCHECK</tt> 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.
+</p>
+</li>
+<li>
+<p>
+It is now possible to specify extra files whose contents should be
+ included in the hash sum by setting the <tt>CCACHE_EXTRAFILES</tt> option.
+</p>
+</li>
+<li>
+<p>
+Added support for Objective-C and Objective-C++. The statistics counter
+ “not a C/C++ file” has been renamed to “unsupported source language”.
+</p>
+</li>
+<li>
+<p>
+Added support for the <tt>-x</tt> compiler option.
+</p>
+</li>
+<li>
+<p>
+Added support for long command-line options.
+</p>
+</li>
+<li>
+<p>
+A <tt>CACHEDIR.TAG</tt> 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 <tt>CCACHE_LOGFILE</tt>) have
+ been improved.
+</p>
+</li>
+<li>
+<p>
+You can relax some checks that ccache does in direct mode by setting
+ <tt>CCACHE_SLOPPINESS</tt>. See the manual for more information.
+</p>
+</li>
+<li>
+<p>
+<tt>CCACHE_TEMPDIR</tt> no longer needs to be on the same filesystem as
+ <tt>CCACHE_DIR</tt>.
+</p>
+</li>
+<li>
+<p>
+The default value of <tt>CCACHE_TEMPDIR</tt> has been changed to
+ <tt>$CCACHE_DIR/tmp</tt> 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’s directory layout.
+</p>
+</li>
+<li>
+<p>
+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.
+</p>
+</li>
+<li>
+<p>
+Standard error output from the compiler is now only stored in the cache
+ if it’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 <tt>CCACHE_PREFIX</tt>, etc.), ccache copes with it
+ properly.
+</p>
+</li>
+<li>
+<p>
+Added <tt>installcheck</tt> and <tt>distcheck</tt> 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:
+ <tt>-imacros</tt>, <tt>-imultilib</tt>, <tt>-iprefix</tt>, <tt>-iquote</tt>, <tt>-isysroot</tt>,
+ <tt>-iwithprefix</tt>, <tt>-iwithprefixbefore</tt>, <tt>-nostdinc</tt>, <tt>-nostdinc++</tt> and
+ <tt>-U</tt>.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_bug_fixes_9">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 <tt>CPPFLAGS</tt> and <tt>LDFLAGS</tt> 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 <tt>-X -Y</tt> and <tt>-X-Y</tt>
+ previously contributed equally to the hash sum.
+</p>
+</li>
+<li>
+<p>
+Bail out on too hard compiler options <tt>--coverage</tt>, <tt>-fprofile-arcs</tt>,
+ <tt>-fprofile-generate</tt>, <tt>-fprofile-use</tt>, <tt>-frepo</tt>, <tt>-ftest-coverage</tt> and
+ <tt>-save-temps</tt>. Also bail out on <tt>@file</tt> style options.
+</p>
+</li>
+<li>
+<p>
+Errors when using multiple <tt>-arch</tt> compiler options are now noted as
+ “unsupported compiler option”.
+</p>
+</li>
+<li>
+<p>
+<tt>-MD</tt>/<tt>-MMD</tt> options without <tt>-MT</tt>/<tt>-MF</tt> are now handled correctly.
+</p>
+</li>
+<li>
+<p>
+The <tt>-finput-charset</tt> option is now handled correctly.
+</p>
+</li>
+<li>
+<p>
+Added support for <tt>-Wp,-MD</tt> and <tt>-Wp,-MMD</tt> options.
+</p>
+</li>
+<li>
+<p>
+The compiler options <tt>-Xassembler</tt>, <tt>-b</tt>, <tt>-G</tt> and <tt>-V</tt> 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 <tt>-g3</tt>) will now be correct.
+</p>
+</li>
+<li>
+<p>
+Corrected LRU cleanup handling of object files.
+</p>
+</li>
+<li>
+<p>
+<tt>utimes()</tt> is now used instead of <tt>utime()</tt> 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 <tt>CCACHE_PREFIX</tt> 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 <tt>x_realloc</tt>.
+</p>
+</li>
+<li>
+<p>
+Freed memory is no longer referenced when compiling a <tt>.i</tt>/<tt>.ii</tt> file and
+ falling back to running the real compiler.
+</p>
+</li>
+<li>
+<p>
+The test suite is now immune to external values of the <tt>CCACHE_*</tt>
+ 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.1.6<br />
+Last updated 2011-08-21 16:34:07 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/NEWS.txt b/NEWS.txt new file mode 100644 index 0000000..febf44e --- /dev/null +++ b/NEWS.txt @@ -0,0 +1,407 @@ +ccache news +=========== + + +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.html b/README.html new file mode 100644 index 0000000..7b50eb9 --- /dev/null +++ b/README.html @@ -0,0 +1,636 @@ +<!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.3" />
+<title>ccache README</title>
+<style type="text/css">
+/* Sans-serif font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+div#toctitle,
+span#author, span#revnumber, span#revdate, span#revremark,
+div#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+/* Serif font. */
+div.sectionbody {
+ font-family: Georgia,"Times New Roman",Times,serif;
+}
+
+/* Monospace font. */
+tt {
+ font-size: inherit;
+}
+
+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;
+}
+
+tt {
+ font-size: inherit;
+ color: navy;
+}
+
+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;
+}
+
+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; }
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+span#email {
+}
+span#revnumber, span#revdate, span#revremark {
+}
+
+div#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.tableblock, 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: #777777;
+}
+
+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; }
+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;
+}
+
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+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;
+}
+
+
+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 {
+ div#footer-badges { display: none; }
+}
+
+div#toc {
+ margin-bottom: 2.5em;
+}
+
+div#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+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;
+}
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+window.onload = function(){asciidoc.footnotes(); asciidoc.toc(2);}
+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]([2-'+(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");
+ 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 () {
+ var cont = document.getElementById("content");
+ var noteholder = document.getElementById("footnotes");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ // 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];
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ 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>]";
+ }
+ }
+ }
+}
+
+}
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>ccache README</h1>
+<span id="revnumber">version 3.1.6</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="_about">About</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<tt>, Objective-C and Objective-C</tt>.</p></div>
+<div class="paragraph"><p>Please see the manual page and documentation at <a href="http://ccache.samba.org">http://ccache.samba.org</a> for
+more information.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_documentation">Documentation</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>See the ccache(1) man page. It’s also available as MANUAL.{txt,html}.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_installation">Installation</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>See INSTALL.{txt.html}.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_web_site">Web site</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The main ccache web site is here:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><tt>http://ccache.samba.org</tt></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_mailing_list">Mailing list</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>There is a mailing list for discussing usage and development of ccache:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><tt>http://lists.samba.org/mailman/listinfo/ccache/</tt></pre>
+</div></div>
+<div class="paragraph"><p>Anyone is welcome to join.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_bug_reports">Bug reports</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>To submit a bug report or to search for existing reports, please visit this web
+page:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><tt>http://ccache.samba.org/bugs.html</tt></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_source_code_repository">Source code repository</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>To get the very latest version of ccache directly from the source code
+repository, use git:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><tt>git clone git://git.samba.org/ccache.git</tt></pre>
+</div></div>
+<div class="paragraph"><p>You can also browse the repository:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><tt>http://gitweb.samba.org/?p=ccache.git</tt></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_history">History</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>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 <a href="http://www.erikyyy.de/compilercache/">http://www.erikyyy.de/compilercache/</a>) in C.</p></div>
+<div class="paragraph"><p>See also NEWS.{txt,html}.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_license_and_copyright">License and copyright</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>See LICENSE.{txt,html} and AUTHORS.{txt,html}.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Version 3.1.6<br />
+Last updated 2010-09-16 19:02:32 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..e7bcc25 --- /dev/null +++ b/README.txt @@ -0,0 +1,81 @@ +ccache README +============= + + +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++. + +Please see the manual page and documentation at http://ccache.samba.org for +more information. + + +Documentation +------------- + +See the ccache(1) man page. It's also available as MANUAL.{txt,html}. + + +Installation +------------ + +See INSTALL.{txt.html}. + + +Web site +-------- + +The main ccache web site is here: + + http://ccache.samba.org + + +Mailing list +------------ + +There is a mailing list for discussing usage and development of ccache: + + http://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: + + http://ccache.samba.org/bugs.html + + +Source code repository +---------------------- + +To get the very latest version of ccache directly from the source code +repository, use git: + + git clone git://git.samba.org/ccache.git + +You can also browse the repository: + + http://gitweb.samba.org/?p=ccache.git + + +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 NEWS.{txt,html}. + + +License and copyright +--------------------- + +See LICENSE.{txt,html} and AUTHORS.{txt,html}. @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2002 Andrew Tridgell + * + * 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; + int i; + args = (struct args *)x_malloc(sizeof(struct args)); + args->argc = 0; + args->argv = (char **)x_malloc(sizeof(char *)); + args->argv[0] = NULL; + for (i = 0; i < init_argc; i++) { + args_add(args, init_args[i]); + } + return args; +} + +struct args * +args_init_from_string(const char *command) +{ + struct args *args; + char *p = x_strdup(command); + char *q = p; + char *word, *saveptr = NULL; + + 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_copy(struct args *args) +{ + return args_init(args->argc, args->argv); +} + +void +args_free(struct args *args) +{ + int i; + if (!args) return; + for (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) +{ + int i; + for (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) +{ + int i; + for (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) +{ + char *result; + char **p; + unsigned size = 0; + int pos; + for (p = args->argv; *p; p++) { + size += strlen(*p) + 1; + } + result = x_malloc(size + 1); + pos = 0; + for (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) +{ + int i; + if (args1->argc != args2->argc) { + return false; + } + for (i = 0; i < args1->argc; i++) { + if (!str_eq(args1->argv[i], args2->argv[i])) { + return false; + } + } + return true; +} + diff --git a/ccache.1 b/ccache.1 new file mode 100644 index 0000000..950b876 --- /dev/null +++ b/ccache.1 @@ -0,0 +1,1365 @@ +'\" t +.\" Title: ccache +.\" Author: [see the "Author" section] +.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/> +.\" Date: 08/21/2011 +.\" Manual: ccache Manual +.\" Source: ccache 3.1.6 +.\" Language: English +.\" +.TH "CCACHE" "1" "08/21/2011" "ccache 3\&.1\&.6" "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 BUGS\&. 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, it\(cqs not needed 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\&. +.RE +.PP +\fB\-F, \-\-max\-files\fR=\fIN\fR +.RS 4 +Set the maximum number of files allowed in the cache\&. The value is stored inside the cache directory and applies to all future compilations\&. Due to the way the value is stored the actual value used is always rounded down to the nearest multiple of 16\&. +.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\&. You can specify a value in gigabytes, megabytes or kilobytes by appending a G, M or K to the value\&. The default is gigabytes\&. The actual value stored is rounded down to the nearest multiple of 16 kilobytes\&. +.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 configured limits)\&. +.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\&. +.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 "ENVIRONMENT VARIABLES" +.sp +ccache uses a number of environment variables to control operation\&. In most cases you won\(cqt need any of these as the defaults will be fine\&. +.PP +\fBCCACHE_BASEDIR\fR +.RS 4 +If you set the environment variable +\fBCCACHE_BASEDIR\fR +to an absolute path to a directory, ccache rewrites absolute paths into relative paths before computing the hash that identifies the compilation, but only for paths under the specified directory\&. See the discussion under +COMPILING IN DIFFERENT DIRECTORIES\&. +.RE +.PP +\fBCCACHE_CC\fR +.RS 4 +You can optionally set +\fBCCACHE_CC\fR +to force the name of the compiler to use\&. If you don\(cqt do this then ccache works it out from the command line\&. +.RE +.PP +\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\&. The +\fBCCACHE_COMPILERCHECK\fR +environment variable 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 +\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 \(lq%compiler%\(rq will be replaced with the path to the compiler\&. Several commands can be specified with semicolon as separator\&. Examples: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} + +%compiler% \-v +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} + +%compiler% \-dumpmachine; %compiler% \-dumpversion +.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 +\fBCCACHE_PREFIX\fR +if possible\&. See +USING CCACHE WITH OTHER COMPILER WRAPPERS\&. +.RE +.RE +.PP +\fBCCACHE_COMPRESS\fR +.RS 4 +If you set the environment variable +\fBCCACHE_COMPRESS\fR +then 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\&. +.RE +.PP +\fBCCACHE_CPP2\fR +.RS 4 +If you set the environment variable +\fBCCACHE_CPP2\fR +then ccache will not use the optimisation of avoiding the second call to the preprocessor by compiling the preprocessed output that was used for finding the hash in the case of a cache miss\&. This is primarily a debugging option, although it is possible that some unusual compilers will have problems with the intermediate filename extensions used in this optimisation, in which case this option could allow ccache to be used anyway\&. +.RE +.PP +\fBCCACHE_DETECT_SHEBANG\fR +.RS 4 +The +\fBCCACHE_DETECT_SHEBANG\fR +environment variable only has meaning on Windows\&. It instructs ccache to open the executable file to detect the +\fB#!/bin/sh\fR +string, in which case ccache will search for +\fBsh\&.exe\fR +in +\fBPATH\fR +and use that to launch the executable\&. +.RE +.PP +\fBCCACHE_DIR\fR +.RS 4 +The +\fBCCACHE_DIR\fR +environment variable specifies where ccache will keep its cached compiler output\&. The default is +\fB$HOME/\&.ccache\fR\&. +.RE +.PP +\fBCCACHE_DISABLE\fR +.RS 4 +If you set the environment variable +\fBCCACHE_DISABLE\fR +then ccache will just call the real compiler, bypassing the cache completely\&. +.RE +.PP +\fBCCACHE_EXTENSION\fR +.RS 4 +ccache tries to automatically determine the extension to use for intermediate preprocessor files based on the type of file being compiled\&. Unfortunately this sometimes doesn\(cqt work, for example when using the \(lqaCC\(rq compiler on HP\-UX\&. On systems like this you can use the +\fBCCACHE_EXTENSION\fR +option to override the default\&. On HP\-UX set this environment variable to +\fBi\fR +if you use the \(lqaCC\(rq compiler\&. +.RE +.PP +\fBCCACHE_EXTRAFILES\fR +.RS 4 +If you set the environment variable +\fBCCACHE_EXTRAFILES\fR +to a list of paths then ccache will include the contents of those files when calculating the hash sum\&. The list separator is semicolon in Windows systems and colon on other systems\&. +.RE +.PP +\fBCCACHE_HARDLINK\fR +.RS 4 +If you set the environment variable +\fBCCACHE_HARDLINK\fR +then 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 set the +\fBCCACHE_COMPRESS\fR +variable if you want to use hard links\&. +.RE +.PP +\fBCCACHE_HASHDIR\fR +.RS 4 +This tells ccache to hash the current working directory when calculating the hash that is used to distinguish two compilations\&. This prevents a problem with the storage of the current working directory in the debug info of a object file, which can lead ccache to give a cached object file that has the working directory in the debug info set incorrectly\&. This option is off by default as the incorrect setting of this debug info rarely causes problems\&. If you strike problems with GDB not using the correct directory then enable this option\&. +.RE +.PP +\fBCCACHE_LOGFILE\fR +.RS 4 +If you set the +\fBCCACHE_LOGFILE\fR +environment variable then ccache will write information on what it is doing to the specified file\&. This is useful for tracking down problems\&. +.RE +.PP +\fBCCACHE_NLEVELS\fR +.RS 4 +The environment variable +\fBCCACHE_NLEVELS\fR +allows you to choose the number of levels of hash in the cache directory\&. The default is 2\&. The minimum is 1 and the maximum is 8\&. +.RE +.PP +\fBCCACHE_NODIRECT\fR +.RS 4 +If you set the environment variable +\fBCCACHE_NODIRECT\fR +then ccache will not use the direct mode\&. +.RE +.PP +\fBCCACHE_NOSTATS\fR +.RS 4 +If you set the environment variable +\fBCCACHE_NOSTATS\fR +then ccache will not update the statistics files on each compilation\&. +.RE +.PP +\fBCCACHE_PATH\fR +.RS 4 +You can optionally set +\fBCCACHE_PATH\fR +to a colon\-separated path where ccache will look for the real compilers\&. If you don\(cqt do this then 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 +\fBCCACHE_PREFIX\fR +.RS 4 +This option adds a prefix to the command line that ccache runs when invoking the compiler\&. Also see the section below on using ccache with \(lqdistcc\(rq\&. +.RE +.PP +\fBCCACHE_READONLY\fR +.RS 4 +The +\fBCCACHE_READONLY\fR +environment variable tells ccache to attempt to use existing cached object files, but not to try to add anything new to the cache\&. If you are using this because your +\fBCCACHE_DIR\fR +is read\-only, then you may find that you also need to set +\fBCCACHE_TEMPDIR\fR +as otherwise ccache will fail to create temporary files\&. +.RE +.PP +\fBCCACHE_RECACHE\fR +.RS 4 +This forces ccache to not use any cached results, even if it finds them\&. New results are still cached, but existing cache entries are ignored\&. +.RE +.PP +\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\&. The +\fBCCACHE_SLOPPINESS\fR +environment variable 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 +\fBinclude_file_mtime\fR +.RS 4 +Don\(cqt check the modification time of include files in the direct mode\&. +.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 +\fBCCACHE_TEMPDIR\fR +.RS 4 +The +\fBCCACHE_TEMPDIR\fR +environment variable specifies where ccache will put temporary files\&. The default is +\fB$CCACHE_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 +\fBCCACHE_UMASK\fR +.RS 4 +This sets 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 +\fBCCACHE_UNIFY\fR +.RS 4 +If you set the environment variable +\fBCCACHE_UNIFY\fR +then 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 using +\fBCCACHE_UNIFY\fR +changes the hash, so cached compilations with +\fBCCACHE_UNIFY\fR +set cannot be used when +\fBCCACHE_UNIFY\fR +is not set and vice versa\&. The reason the unifier is off by default is that it can give incorrect line number information in compiler warning messages\&. Also note that enabling the unifier implies turning off the direct mode\&. +.RE +.SH "CACHE SIZE MANAGEMENT" +.sp +By default ccache has a one 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 involves a negligible performance slowdown, it significantly increases the number of files that fit in the cache\&. You can turn on compression by setting the \fBCCACHE_COMPRESS\fR environment variable\&. +.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 +\fBCCACHE_COMPILERCHECK\fR) +.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 +\fBCCACHE_HASHDIR\fR +is set) +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +contents of files specified by +\fBCCACHE_EXTRAFILES\fR +(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 +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 environment variable +\fBCCACHE_NODIRECT\fR +is set +.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 environment variable +\fBCCACHE_UNIFY\fR +is set) +.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 +and +\fB\-Wp,\-MMD,\fR\fB\fIpath\fR\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 outside comments and string literals 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 by setting the \fBCCACHE_BASEDIR\fR variable 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 \fBCCACHE_BASEDIR\fR 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 +\fBCCACHE_SLOPPINESS\fR +to +\fBtime_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\&. +.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 +.\} +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 +\fBCCACHE_DIR\fR +environment variable setting\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Unset the +\fBCCACHE_HARDLINK\fR +environment variable\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Make sure everyone sets the +\fBCCACHE_UMASK\fR +environment variable 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 command \(lqfind $CCACHE_DIR \-type d | xargs chmod g+s\(rq might be useful for this\&. +.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 the developers have \fBCCACHE_BASEDIR\fR set appropriately, as discussed in the 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 \fBCCACHE_TEMPDIR\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 using the \fBCCACHE_PREFIX\fR option\&. You just need to set the environment variable \fBCCACHE_PREFIX\fR to the name of the wrapper (e\&.g\&. \fBdistcc\fR) and ccache will prefix the command line with the specified command when running the compiler\&. +.sp +Unless you set \fBCCACHE_COMPILERCHECK\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 \fBCCACHE_PREFIX\fR is not used, ccache will needlessly invoke the other wrapper when running the preprocessor\&. +.SH "BUGS" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +ccache doesn\(cqt handle the GNU Assembler\(cqs +\fB\&.incbin\fR +directive correctly\&. This directive can be embedded in the source code inside an +\fB\fIasm\fR\fR +statement in order to include a file verbatim in the object file\&. If the included file is modified, ccache doesn\(cqt pick up the change since the inclusion isn\(cqt done by the preprocessor\&. A workaround of this problem is to set +\fBCCACHE_EXTRAFILES\fR +to the path of the included file\&. +.RE +.SH "TROUBLESHOOTING" +.SS "General" +.sp +A general tip for getting information about what ccache is doing is to enable debug logging by setting \fBCCACHE_LOGFILE\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 preferrable\&. +.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 +and +\fBWp,\-MMD,\fR\fB\fIpath\fR\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 +\fBCCACHE_BASEDIR\fR\&. +.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 +\fBCCACHE_SLOPPINESS\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 outside comments and string literals\&. 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 +\fBCCACHE_SLOPPINESS\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 outside comments and string literals, 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 +\fBCCACHE_SLOPPINESS\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 outside comments and string literals, 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 +\fBCCACHE_SLOPPINESS\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 "Errors when compiling with ccache" +.sp +If compilation doesn\(cqt work with ccache, but it works without it, one possible reason is that the compiler can\(cqt compile preprocessed output correctly\&. A workaround that may work is to set \fBCCACHE_CPP2\fR\&. This will make cache misses slower, though, so it is better to find and fix the root cause\&. +.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 \fBCCACHE_PREFIX\fR command or compiler wrapper\&. If this happens, you can either find out which object file is broken by reading the debug log and then delete the bad object file from the cache, or you can simply 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: http://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 http://ccache\&.samba\&.org/credits\&.html for a list of contributors\&. diff --git a/ccache.c b/ccache.c new file mode 100644 index 0000000..3bb6d77 --- /dev/null +++ b/ccache.c @@ -0,0 +1,2190 @@ +/* + * ccache -- a fast C/C++ compiler cache + * + * Copyright (C) 2002-2007 Andrew Tridgell + * Copyright (C) 2009-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 "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" + +static const char VERSION_TEXT[] = +MYNAME " version %s\n" +"\n" +"Copyright (C) 2002-2007 Andrew Tridgell\n" +"Copyright (C) 2009-2011 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\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: G, M and K; default\n" +" suffix: G)\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 <http://ccache.samba.org>.\n"; + +/* current working directory taken from $PWD, or getcwd() if $PWD is bad */ +char *current_working_dir = NULL; + +/* the base cache directory */ +char *cache_dir = NULL; + +/* the directory for temporary files */ +static char *temp_dir; + +/* the debug logfile name, if set */ +char *cache_logfile = NULL; + +/* base directory (from CCACHE_BASEDIR) */ +char *base_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; + +/* + * 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 manifest + * (cachedir/a/b/cdef[...]-size.manifest). + */ +static char *manifest_path; + +/* + * Time of compilation. Used to see if include files have changed after + * compilation. + */ +static time_t time_of_compilation; + +/* Bitmask of SLOPPY_*. */ +unsigned sloppiness = 0; + +/* + * Files included by the preprocessor and their hashes/sizes. Key: file path. + * Value: struct file_hash. + */ +static struct hashtable *included_files; + +/* is gcc being asked to output dependencies? */ +static bool generating_dependencies; + +/* the extension of the file (without dot) after pre-processing */ +static const char *i_extension; + +/* the name of the temporary pre-processor 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 (CCACHE_DIR/X/stats). + */ +char *stats_file = NULL; + +/* can we safely use the unification hashing backend? */ +static bool enable_unify; + +/* should we use the direct mode? */ +static bool enable_direct = true; + +/* + * Whether to enable compression of files stored in the cache. (Manifest files + * are always compressed.) + */ +static bool enable_compression = false; + +/* number of levels (1 <= nlevels <= 8) */ +static int nlevels = 2; + +/* + * Whether we should use the optimization of passing the already existing + * preprocessed source code to the compiler. + */ +static bool compile_preprocessed_source_code; + +/* Whether the output is a precompiled header */ +static bool output_is_precompiled_header = false; + +/* + * Whether we are using a precompiled header (either via -include or #include). + */ +static bool using_precompiled_header = false; + +/* 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, + FROMCACHE_COMPILED_MODE +}; + +/* + * 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"; + +/* Something went badly wrong - just execute the real compiler. */ +static void +failed(void) +{ + char *e; + + /* strip any local args */ + args_strip(orig_args, "--ccache-"); + + if ((e = getenv("CCACHE_PREFIX"))) { + char *p = find_executable(e, MYNAME); + if (!p) { + fatal("%s: %s", e, strerror(errno)); + } + args_add_prefix(orig_args, p); + } + + 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("%s: execv returned (%s)", orig_args->argv[0], strerror(errno)); +} + +static void +clean_up_tmp_files() +{ + /* delete intermediate pre-processor file if needed */ + if (i_tmpfile) { + if (!direct_i_file) { + tmp_unlink(i_tmpfile); + } + free(i_tmpfile); + i_tmpfile = NULL; + } + + /* delete the cpp stderr file if necessary */ + if (cpp_stderr) { + tmp_unlink(cpp_stderr); + free(cpp_stderr); + cpp_stderr = NULL; + } +} + +/* + * 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) +{ + int i; + char *path; + char *result; + + path = x_strdup(cache_dir); + for (i = 0; i < nlevels; ++i) { + char *p = format("%s/%c", path, name[i]); + free(path); + path = p; + if (create_dir(path) != 0) { + cc_log("Failed to create %s: %s", path, strerror(errno)); + failed(); + } + } + result = format("%s/%s%s", path, name + nlevels, 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, size_t path_len, struct mdfour *cpp_hash) +{ + struct mdfour fhash; + struct stat st; + char *source = NULL; + size_t size; + int result; + bool is_pch; + + 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 (hashtable_search(included_files, path)) { + /* Already known include file. */ + goto ignore; + } + + if (stat(path, &st) != 0) { + cc_log("Failed to stat include file %s: %s", path, strerror(errno)); + 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; + } + + /* Let's hash the include file. */ + if (!(sloppiness & SLOPPY_INCLUDE_FILE_MTIME) + && st.st_mtime >= time_of_compilation) { + cc_log("Include file %s too new", path); + goto failure; + } + + hash_start(&fhash); + + is_pch = is_precompiled_header(path); + if (is_pch) { + struct file_hash pch_hash; + if (!hash_file(&fhash, path)) { + goto failure; + } + 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 (enable_direct) { + struct file_hash *h; + + if (!is_pch) { /* else: the file has already been hashed. */ + if (st.st_size > 0) { + if (!read_file(path, st.st_size, &source, &size)) { + goto failure; + } + } else { + source = x_strdup(""); + size = 0; + } + + result = hash_source_code_string(&fhash, source, size, path); + if (result & HASH_SOURCE_CODE_ERROR + || result & HASH_SOURCE_CODE_FOUND_TIME) { + goto failure; + } + } + + 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); + } + + free(source); + return; + +failure: + cc_log("Disabling direct mode"); + enable_direct = false; + /* Fall through. */ +ignore: + free(path); + free(source); +} + +/* + * Make a relative path from CCACHE_BASEDIR to path. Takes over ownership of + * path. Caller frees. + */ +static char * +make_relative_path(char *path) +{ + char *relpath; + + if (!base_dir || !str_startswith(path, base_dir)) { + return path; + } + + relpath = get_relative_path(current_working_dir, path); + free(path); + return relpath; +} + +/* + * This function reads and hashes a file. While doing this, it also does these + * things: + * + * - Makes include file paths whose prefix is CCACHE_BASEDIR 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; + char *p, *q, *end; + size_t size; + + if (!read_file(path, 0, &data, &size)) { + return false; + } + + included_files = create_hashtable(1000, hash_from_string, strings_equal); + + /* Bytes between p and q are pending to be hashed. */ + end = data + size; + p = data; + q = data; + while (q < end - 7) { /* There must be at least 7 characters (# 1 "x") left + to potentially find an include file path. */ + /* + * 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')) { + char *path; + + 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++; + } + /* p and q span the include file path */ + path = x_strndup(p, q - p); + path = make_relative_path(path); + hash_string(hash, path); + remember_include_file(path, q - p, hash); + p = q; + } else { + q++; + } + } + + hash_buffer(hash, p, (end - p)); + free(data); + return true; +} + +/* run the real compiler and put the result in cache */ +static void +to_cache(struct args *args) +{ + char *tmp_stdout, *tmp_stderr, *tmp_obj; + struct stat st; + int status; + size_t added_bytes = 0; + unsigned added_files = 0; + + tmp_stdout = format("%s.tmp.stdout.%s", cached_obj, tmp_string()); + tmp_stderr = format("%s.tmp.stderr.%s", cached_obj, tmp_string()); + tmp_obj = format("%s.tmp.%s", cached_obj, tmp_string()); + + args_add(args, "-o"); + args_add(args, tmp_obj); + + /* Turn off DEPENDENCIES_OUTPUT when running cc1, because + * otherwise it will emit a line like + * + * tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i + * + * unsetenv() is on BSD and Linux but not portable. */ + putenv("DEPENDENCIES_OUTPUT"); + + if (compile_preprocessed_source_code) { + args_add(args, i_tmpfile); + } else { + args_add(args, input_file); + } + + cc_log("Running real compiler"); + status = execute(args->argv, tmp_stdout, tmp_stderr); + args_pop(args, 3); + + if (stat(tmp_stdout, &st) != 0 || st.st_size != 0) { + cc_log("Compiler produced stdout"); + stats_update(STATS_STDOUT); + tmp_unlink(tmp_stdout); + tmp_unlink(tmp_stderr); + tmp_unlink(tmp_obj); + failed(); + } + tmp_unlink(tmp_stdout); + + /* + * Merge stderr from the preprocessor (if any) and stderr from the real + * compiler into tmp_stderr. + */ + if (cpp_stderr) { + int fd_cpp_stderr; + int fd_real_stderr; + int fd_result; + char *tmp_stderr2; + + tmp_stderr2 = format("%s.tmp.stderr2.%s", cached_obj, tmp_string()); + if (x_rename(tmp_stderr, tmp_stderr2)) { + cc_log("Failed to rename %s to %s: %s", tmp_stderr, tmp_stderr2, + strerror(errno)); + failed(); + } + 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(); + } + 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(); + } + 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) { + int fd; + cc_log("Compiler gave exit status %d", status); + stats_update(STATS_STATUS); + + fd = open(tmp_stderr, O_RDONLY | O_BINARY); + if (fd != -1) { + if (str_eq(output_obj, "/dev/null") + || (access(tmp_obj, R_OK) == 0 + && move_file(tmp_obj, output_obj, 0) == 0) + || errno == ENOENT) { + /* we can use a quick method of getting the failed output */ + copy_fd(fd, 2); + close(fd); + tmp_unlink(tmp_stderr); + exit(status); + } + } + + tmp_unlink(tmp_stderr); + tmp_unlink(tmp_obj); + failed(); + } + + if (stat(tmp_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 (stat(tmp_stderr, &st) != 0) { + cc_log("Failed to stat %s: %s", tmp_stderr, strerror(errno)); + stats_update(STATS_ERROR); + failed(); + } + if (st.st_size > 0) { + if (move_uncompressed_file(tmp_stderr, cached_stderr, + enable_compression) != 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 (enable_compression) { + stat(cached_stderr, &st); + } + added_bytes += file_size(&st); + added_files += 1; + } else { + tmp_unlink(tmp_stderr); + } + if (move_uncompressed_file(tmp_obj, cached_obj, enable_compression) != 0) { + cc_log("Failed to move %s to %s: %s", tmp_obj, cached_obj, strerror(errno)); + stats_update(STATS_ERROR); + failed(); + } else { + cc_log("Stored in cache: %s", cached_obj); + stat(cached_obj, &st); + added_bytes += file_size(&st); + added_files += 1; + } + + /* + * Do an extra stat on the potentially compressed object file for the + * size statistics. + */ + if (stat(cached_obj, &st) != 0) { + cc_log("Failed to stat %s: %s", cached_obj, strerror(errno)); + stats_update(STATS_ERROR); + failed(); + } + + stats_update_size(STATS_TOCACHE, added_bytes / 1024, added_files); + + free(tmp_obj); + free(tmp_stderr); + free(tmp_stdout); +} + +/* + * 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) +{ + char *input_base; + char *tmp; + char *path_stdout, *path_stderr; + int status; + struct file_hash *result; + + /* ~/hello.c -> tmp.hello.123.i + limit the basename to 10 + characters in order to cope with filesystem with small + maximum filename length limits */ + input_base = basename(input_file); + tmp = strchr(input_base, '.'); + if (tmp != NULL) { + *tmp = 0; + } + if (strlen(input_base) > 10) { + input_base[10] = 0; + } + + /* now the run */ + path_stdout = format("%s/%s.tmp.%s.%s", + temp_dir, input_base, tmp_string(), i_extension); + path_stderr = format("%s/tmp.cpp_stderr.%s", temp_dir, tmp_string()); + + time_of_compilation = time(NULL); + + if (!direct_i_file) { + /* run cpp on the input file to obtain the .i */ + args_add(args, "-E"); + args_add(args, input_file); + status = execute(args->argv, path_stdout, path_stderr); + args_pop(args, 2); + } else { + /* 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; + if (create_empty_file(path_stderr) != 0) { + cc_log("Failed to create %s: %s", path_stderr, strerror(errno)); + stats_update(STATS_ERROR); + failed(); + } + status = 0; + } + + if (status != 0) { + if (!direct_i_file) { + tmp_unlink(path_stdout); + } + tmp_unlink(path_stderr); + cc_log("Preprocessor gave exit status %d", status); + stats_update(STATS_PREPROCESSOR); + failed(); + } + + if (enable_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); + tmp_unlink(path_stderr); + 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); + tmp_unlink(path_stderr); + failed(); + } + } + + hash_delimiter(hash, "cppstderr"); + if (!hash_file(hash, path_stderr)) { + fatal("Failed to open %s: %s", path_stderr, strerror(errno)); + } + + i_tmpfile = path_stdout; + + if (compile_preprocessed_source_code) { + /* + * 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; + } else { + tmp_unlink(path_stderr); + free(path_stderr); + } + + 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; + + 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"); + stats_file = format("%s/%c/stats", cache_dir, object_name[0]); + free(object_name); +} + +/* + * Update a hash sum with information common for the direct and preprocessor + * modes. + */ +static void +calculate_common_hash(struct args *args, struct mdfour *hash) +{ + struct stat st; + const char *compilercheck; + char *p; + + 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, i_extension); + + if (stat(args->argv[0], &st) != 0) { + cc_log("Couldn't stat compiler %s: %s", args->argv[0], strerror(errno)); + stats_update(STATS_COMPILER); + failed(); + } + + /* + * Hash information about the compiler. + */ + compilercheck = getenv("CCACHE_COMPILERCHECK"); + if (!compilercheck) { + compilercheck = "mtime"; + } + if (str_eq(compilercheck, "none")) { + /* Do nothing. */ + } else if (str_eq(compilercheck, "content")) { + hash_delimiter(hash, "cc_content"); + hash_file(hash, args->argv[0]); + } else if (str_eq(compilercheck, "mtime")) { + hash_delimiter(hash, "cc_mtime"); + hash_int(hash, st.st_size); + hash_int(hash, st.st_mtime); + } else { /* command string */ + if (!hash_multicommand_output(hash, compilercheck, orig_args->argv[0])) { + fatal("Failure running compiler check command: %s", compilercheck); + } + } + + /* + * Also hash the compiler name as some compilers use hard links and + * behave differently depending on the real name. + */ + hash_delimiter(hash, "cc_name"); + hash_string(hash, basename(args->argv[0])); + + /* Possibly hash the current working directory. */ + if (getenv("CCACHE_HASHDIR")) { + char *cwd = gnu_getcwd(); + if (cwd) { + hash_delimiter(hash, "cwd"); + hash_string(hash, cwd); + free(cwd); + } + } + + p = getenv("CCACHE_EXTRAFILES"); + if (p) { + char *path, *q, *saveptr = NULL; + p = x_strdup(p); + q = p; + 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); + } +} + +/* + * 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) +{ + int i; + char *manifest_name; + struct stat st; + int result; + struct file_hash *object_hash = NULL; + + /* first the arguments */ + for (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; + } + + /* 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 (str_startswith(args->argv[i], "--specs=") && + stat(args->argv[i] + 8, &st) == 0) { + /* If given a explicit specs file, then hash that file, + but don't include the path to it in the hash. */ + hash_delimiter(hash, "specs"); + if (!hash_file(hash, args->argv[i] + 8)) { + failed(); + } + continue; + } + + /* All other arguments are included in the hash. */ + hash_delimiter(hash, "arg"); + hash_string(hash, args->argv[i]); + } + + if (direct_mode) { + if (!(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"); + result = hash_source_code_file(hash, input_file); + if (result & HASH_SOURCE_CODE_ERROR) { + failed(); + } + if (result & HASH_SOURCE_CODE_FOUND_TIME) { + cc_log("Disabling direct mode"); + enable_direct = false; + return NULL; + } + 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(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 { + object_hash = get_object_name_from_cpp(args, hash); + cc_log("Got object file hash from preprocessor"); + 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) +{ + int fd_stderr; + int ret; + struct stat st; + bool produce_dep_file; + + /* the user might be disabling cache hits */ + if (mode != FROMCACHE_COMPILED_MODE && getenv("CCACHE_RECACHE")) { + return; + } + + /* Check if the object file is there. */ + if (stat(cached_obj, &st) != 0) { + cc_log("Object file %s not in cache", cached_obj); + return; + } + + /* + * (If mode != FROMCACHE_DIRECT_MODE, the dependency file is created by + * gcc.) + */ + 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; + } + + if (str_eq(output_obj, "/dev/null")) { + ret = 0; + } else { + x_unlink(output_obj); + /* only make a hardlink if the cache file is uncompressed */ + if (getenv("CCACHE_HARDLINK") && !file_is_compressed(cached_obj)) { + ret = link(cached_obj, output_obj); + } else { + ret = copy_file(cached_obj, output_obj, 0); + } + } + + if (ret == -1) { + if (errno == ENOENT) { + /* Someone removed the file just before we began copying? */ + cc_log("Object file %s just disappeared from cache", cached_obj); + stats_update(STATS_MISSING); + } else { + cc_log("Failed to copy/link %s to %s: %s", + cached_obj, output_obj, strerror(errno)); + stats_update(STATS_ERROR); + failed(); + } + x_unlink(output_obj); + x_unlink(cached_stderr); + x_unlink(cached_obj); + x_unlink(cached_dep); + return; + } else { + cc_log("Created %s from %s", output_obj, cached_obj); + } + + if (produce_dep_file) { + x_unlink(output_dep); + /* only make a hardlink if the cache file is uncompressed */ + if (getenv("CCACHE_HARDLINK") && !file_is_compressed(cached_dep)) { + ret = link(cached_dep, output_dep); + } else { + ret = copy_file(cached_dep, output_dep, 0); + } + if (ret == -1) { + if (errno == ENOENT) { + /* + * Someone removed the file just before we + * began copying? + */ + cc_log("Dependency file %s just disappeared from cache", output_obj); + stats_update(STATS_MISSING); + } else { + cc_log("Failed to copy/link %s to %s: %s", + cached_dep, output_dep, strerror(errno)); + stats_update(STATS_ERROR); + failed(); + } + x_unlink(output_obj); + x_unlink(output_dep); + x_unlink(cached_stderr); + x_unlink(cached_obj); + x_unlink(cached_dep); + return; + } else { + cc_log("Created %s from %s", output_dep, cached_dep); + } + } + + /* 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_dependencies && mode != FROMCACHE_DIRECT_MODE) { + /* Store the dependency file in the cache. */ + ret = copy_file(output_dep, cached_dep, enable_compression); + if (ret == -1) { + cc_log("Failed to copy %s to %s: %s", output_dep, cached_dep, + strerror(errno)); + /* Continue despite the error. */ + } else { + cc_log("Stored in cache: %s", cached_dep); + stat(cached_dep, &st); + stats_update_size(STATS_NONE, file_size(&st) / 1024, 1); + } + } + + /* Send the stderr, if any. */ + 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. */ + if (enable_direct + && put_object_in_manifest + && included_files + && !getenv("CCACHE_READONLY")) { + 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); + stat(manifest_path, &st); + stats_update_size(STATS_NONE, + (file_size(&st) - old_size) / 1024, + old_size == 0 ? 1 : 0); + } else { + cc_log("Failed to add object file hash to %s", manifest_path); + } + } + + /* log the cache hit */ + switch (mode) { + case FROMCACHE_DIRECT_MODE: + cc_log("Succeded getting cached result"); + stats_update(STATS_CACHEHIT_DIR); + break; + + case FROMCACHE_CPP_MODE: + cc_log("Succeded getting cached result"); + stats_update(STATS_CACHEHIT_CPP); + break; + + case FROMCACHE_COMPILED_MODE: + /* Stats already updated in to_cache(). */ + break; + } + + /* and exit with the right status code */ + exit(0); +} + +/* find the real compiler. We just search the PATH to find a executable of the + same name that isn't a link to ourselves */ +static void +find_compiler(int argc, char **argv) +{ + char *base; + char *path; + char *compiler; + + orig_args = args_init(argc, argv); + + base = basename(argv[0]); + + /* we might be being invoked like "ccache gcc -c foo.c" */ + if (same_executable_name(base, MYNAME)) { + args_remove_first(orig_args); + free(base); + if (is_full_path(argv[1])) { + /* a full path was given */ + return; + } + base = basename(argv[1]); + } + + /* support user override of the compiler */ + if ((path = getenv("CCACHE_CC"))) { + base = x_strdup(path); + } + + compiler = find_executable(base, MYNAME); + + /* can't find the compiler! */ + 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"); +} + +/* + * 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 *orig_args, struct args **preprocessor_args, + struct args **compiler_args) +{ + int i; + bool found_c_opt = false; + bool found_S_opt = false; + bool found_arch_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; + struct stat st; + /* 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; + struct args *stripped_args = NULL, *dep_args = NULL; + int argc = orig_args->argc; + char **argv = orig_args->argv; + bool result = true; + + stripped_args = args_init(0, NULL); + dep_args = args_init(0, NULL); + + args_add(stripped_args, argv[0]); + + for (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; + } + + /* These are always too hard. */ + if (compopt_too_hard(argv[i]) + || str_startswith(argv[i], "@") + || str_startswith(argv[i], "-fdump-")) { + cc_log("Compiler option %s is unsupported", argv[i]); + stats_update(STATS_UNSUPPORTED); + result = false; + goto out; + } + + /* These are too hard in direct mode. */ + if (enable_direct) { + if (compopt_too_hard_for_direct_mode(argv[i])) { + cc_log("Unsupported compiler option for direct mode: %s", argv[i]); + enable_direct = false; + } + } + + /* Multiple -arch options are too hard. */ + if (str_eq(argv[i], "-arch")) { + if (found_arch_opt) { + cc_log("More than one -arch compiler option is unsupported"); + stats_update(STATS_UNSUPPORTED); + result = false; + goto out; + } else { + found_arch_opt = true; + } + } + + if (str_eq(argv[i], "-fpch-preprocess")) { + found_fpch_preprocess = true; + } + + /* we must have -c */ + if (str_eq(argv[i], "-c")) { + args_add(stripped_args, argv[i]); + 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 = argv[i+1]; + i++; + continue; + } + + /* alternate form of -o, with no space */ + if (str_startswith(argv[i], "-o")) { + output_obj = &argv[i][2]; + continue; + } + + /* debugging is handled specially, so that we know if we + can strip line number info + */ + if (str_startswith(argv[i], "-g")) { + args_add(stripped_args, argv[i]); + if (enable_unify && !str_eq(argv[i], "-g0")) { + cc_log("%s used; disabling unify mode", argv[i]); + enable_unify = false; + } + if (str_eq(argv[i], "-g3")) { + /* + * Fix for bug 7190 ("commandline macros (-D) + * have non-zero lineno when using -g3"). + */ + cc_log("%s used; not compiling preprocessed code", argv[i]); + compile_preprocessed_source_code = false; + } + 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")) { + char *arg; + dependency_filename_specified = true; + free(output_dep); + args_add(dep_args, argv[i]); + if (strlen(argv[i]) == 3) { + /* -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]; + args_add(dep_args, argv[i + 1]); + i++; + } else { + /* -MFarg */ + arg = &argv[i][3]; + } + output_dep = make_relative_path(x_strdup(arg)); + continue; + } + if (str_startswith(argv[i], "-MQ") || str_startswith(argv[i], "-MT")) { + args_add(dep_args, argv[i]); + 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 + 1]); + i++; + /* + * Yes, that's right. It's strange, but apparently, GCC behaves + * differently for -MT arg and -MTarg (and similar for -MQ): in the + * latter case, but not in the former, an implicit dependency for the + * object file is added to the dependency file. + */ + dependency_target_specified = true; + } + 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_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 (enable_direct) { + /* + * -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]); + enable_direct = false; + } + } + 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; + } + + /* + * Options taking an argument that 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])) { + char *relpath; + char *pchpath; + if (i == argc-1) { + cc_log("Missing argument to %s", argv[i]); + stats_update(STATS_ARGS); + result = false; + goto out; + } + + args_add(stripped_args, argv[i]); + relpath = make_relative_path(x_strdup(argv[i+1])); + args_add(stripped_args, relpath); + + /* Try to be smart about detecting precompiled headers */ + pchpath = format("%s.gch", argv[i+1]); + if (stat(pchpath, &st) == 0) { + cc_log("Detected use of precompiled header: %s", pchpath); + found_pch = true; + } + + free(pchpath); + free(relpath); + i++; + continue; + } + + /* Same as above but options with concatenated argument. */ + if (compopt_short(compopt_takes_path, argv[i])) { + char *relpath; + char *option; + relpath = make_relative_path(x_strdup(argv[i] + 2)); + option = format("-%c%s", argv[i][1], relpath); + args_add(stripped_args, option); + free(relpath); + free(option); + continue; + } + + /* 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; + } + args_add(stripped_args, argv[i]); + args_add(stripped_args, argv[i+1]); + i++; + continue; + } + + /* other options */ + if (argv[i][0] == '-') { + 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 */ + 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; + } + + /* Rewrite to relative to increase hit rate. */ + input_file = make_relative_path(x_strdup(argv[i])); + } + + 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 (!(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") != NULL; + + if (!found_c_opt && !output_is_precompiled_header) { + 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) { + /* It doesn't work to create the .gch from preprocessed source. */ + cc_log("Creating precompiled header; not compiling preprocessed code"); + compile_preprocessed_source_code = false; + } + + i_extension = getenv("CCACHE_EXTENSION"); + if (!i_extension) { + const char *p_language = p_language_for_language(actual_language); + i_extension = 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 { + char *p; + output_obj = x_strdup(input_file); + if ((p = strrchr(output_obj, '/'))) { + output_obj = p+1; + } + 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; + } + } + + /* cope with -o /dev/null */ + 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) + */ + *preprocessor_args = args_copy(stripped_args); + if (input_charset) { + args_add(*preprocessor_args, input_charset); + } + if (found_pch) { + args_add(*preprocessor_args, "-fpch-preprocess"); + } + if (explicit_language) { + args_add(*preprocessor_args, "-x"); + args_add(*preprocessor_args, explicit_language); + } + + /* + * Add flags for dependency generation only to the preprocessor command line. + */ + if (generating_dependencies) { + if (!dependency_filename_specified) { + char *default_depfile_name; + char *base_name; + + base_name = remove_extension(output_obj); + 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 (compile_preprocessed_source_code) { + *compiler_args = args_copy(stripped_args); + 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)); + } + } else { + *compiler_args = args_copy(*preprocessor_args); + } + + /* + * 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(*preprocessor_args, dep_args); + +out: + args_free(stripped_args); + args_free(dep_args); + return result; +} + +/* Reset the global state. Used by the test suite. */ +void +cc_reset(void) +{ + free(current_working_dir); current_working_dir = NULL; + free(cache_dir); cache_dir = NULL; + cache_logfile = NULL; + base_dir = NULL; + args_free(orig_args); orig_args = NULL; + free(input_file); input_file = NULL; + output_obj = NULL; + free(output_dep); output_dep = NULL; + free(cached_obj_hash); cached_obj_hash = NULL; + free(cached_obj); cached_obj = NULL; + free(cached_stderr); cached_stderr = NULL; + free(cached_dep); cached_dep = NULL; + free(manifest_path); manifest_path = NULL; + time_of_compilation = 0; + sloppiness = false; + if (included_files) { + hashtable_destroy(included_files, 1); included_files = NULL; + } + generating_dependencies = false; + i_extension = NULL; + i_tmpfile = NULL; + direct_i_file = false; + free(cpp_stderr); cpp_stderr = NULL; + free(stats_file); stats_file = NULL; + enable_unify = false; + enable_direct = true; + enable_compression = false; + nlevels = 2; + compile_preprocessed_source_code = false; + output_is_precompiled_header = false; +} + +static unsigned +parse_sloppiness(char *p) +{ + unsigned result = 0; + char *word, *q, *saveptr = NULL; + + if (!p) { + return result; + } + p = x_strdup(p); + q = p; + while ((word = strtok_r(q, ", ", &saveptr))) { + if (str_eq(word, "file_macro")) { + cc_log("Being sloppy about __FILE__"); + result |= SLOPPY_FILE_MACRO; + } + if (str_eq(word, "include_file_mtime")) { + cc_log("Being sloppy about include file mtime"); + result |= SLOPPY_INCLUDE_FILE_MTIME; + } + if (str_eq(word, "time_macros")) { + cc_log("Being sloppy about __DATE__ and __TIME__"); + result |= SLOPPY_TIME_MACROS; + } + q = NULL; + } + free(p); + return result; +} + +/* the main ccache driver function */ +static void +ccache(int argc, char *argv[]) +{ + bool put_object_in_manifest = false; + struct file_hash *object_hash; + struct file_hash *object_hash_from_manifest = NULL; + char *env; + struct mdfour common_hash; + struct mdfour direct_hash; + struct mdfour cpp_hash; + + /* Arguments (except -E) to send to the preprocessor. */ + struct args *preprocessor_args; + + /* Arguments to send to the real compiler. */ + struct args *compiler_args; + + find_compiler(argc, argv); + + if (getenv("CCACHE_DISABLE")) { + cc_log("ccache is disabled"); + failed(); + } + + sloppiness = parse_sloppiness(getenv("CCACHE_SLOPPINESS")); + + cc_log_argv("Command line: ", argv); + cc_log("Hostname: %s", get_hostname()); + cc_log("Working directory: %s", current_working_dir); + + if (base_dir) { + cc_log("Base directory: %s", base_dir); + } + + if (getenv("CCACHE_UNIFY")) { + cc_log("Unify mode disabled"); + enable_unify = true; + } + + if (getenv("CCACHE_NODIRECT") || enable_unify) { + cc_log("Direct mode disabled"); + enable_direct = false; + } + + if (getenv("CCACHE_COMPRESS")) { + cc_log("Compression enabled"); + enable_compression = true; + } + + if ((env = getenv("CCACHE_NLEVELS"))) { + nlevels = atoi(env); + if (nlevels < 1) nlevels = 1; + if (nlevels > 8) nlevels = 8; + } + + 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); + } + cc_log("Object file: %s", output_obj); + + hash_start(&common_hash); + calculate_common_hash(preprocessor_args, &common_hash); + + /* try to find the hash using the manifest */ + direct_hash = common_hash; + if (enable_direct) { + 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; + } + } + + /* + * Find the hash using the preprocessed output. Also updates + * included_files. + */ + cpp_hash = common_hash; + cc_log("Running preprocessor"); + 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 (getenv("CCACHE_READONLY")) { + cc_log("Read-only mode; running real compiler"); + failed(); + } + + env = getenv("CCACHE_PREFIX"); + if (env) { + char *p = find_executable(env, MYNAME); + if (!p) { + fatal("%s: %s", env, strerror(errno)); + } + cc_log("Using command-line prefix %s", env); + args_add_prefix(compiler_args, p); + } + + /* run real compiler, sending output to cache */ + to_cache(compiler_args); + + /* return from cache */ + from_cache(FROMCACHE_COMPILED_MODE, put_object_in_manifest); + + /* oh oh! */ + cc_log("Secondary from_cache failed"); + stats_update(STATS_ERROR); + failed(); +} + +static void +check_cache_dir(void) +{ + if (!cache_dir) { + fatal("Unable to determine cache directory"); + } +} + +/* the main program when not doing a compile */ +static int +ccache_main_options(int argc, char *argv[]) +{ + int c; + size_t v; + + static const struct option options[] = { + {"show-stats", no_argument, 0, 's'}, + {"zero-stats", no_argument, 0, 'z'}, + {"cleanup", no_argument, 0, 'c'}, + {"clear", no_argument, 0, 'C'}, + {"max-files", required_argument, 0, 'F'}, + {"max-size", required_argument, 0, 'M'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0} + }; + + while ((c = getopt_long(argc, argv, "hszcCF:M:V", options, NULL)) != -1) { + switch (c) { + case 'V': + fprintf(stdout, VERSION_TEXT, CCACHE_VERSION); + exit(0); + + case 'h': + fputs(USAGE_TEXT, stdout); + exit(0); + + case 's': + check_cache_dir(); + stats_summary(); + break; + + case 'c': + check_cache_dir(); + cleanup_all(cache_dir); + printf("Cleaned cache\n"); + break; + + case 'C': + check_cache_dir(); + wipe_all(cache_dir); + printf("Cleared cache\n"); + break; + + case 'z': + check_cache_dir(); + stats_zero(); + printf("Statistics cleared\n"); + break; + + case 'F': + check_cache_dir(); + v = atoi(optarg); + if (stats_set_limits(v, -1) == 0) { + if (v == 0) { + printf("Unset cache file limit\n"); + } else { + printf("Set cache file limit to %u\n", (unsigned)v); + } + } else { + printf("Could not set cache file limit.\n"); + exit(1); + } + break; + + case 'M': + check_cache_dir(); + v = value_units(optarg); + if (stats_set_limits(-1, v) == 0) { + if (v == 0) { + printf("Unset cache size limit\n"); + } else { + char *s = format_size(v); + printf("Set cache size limit to %s\n", s); + free(s); + } + } else { + printf("Could not set cache size limit.\n"); + exit(1); + } + break; + + default: + fputs(USAGE_TEXT, stderr); + exit(1); + } + } + + return 0; +} + + +/* 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) +{ + char *buf; + int uncached_fd; + + uncached_fd = dup(2); + if (uncached_fd == -1) { + cc_log("dup(2) failed: %s", strerror(errno)); + failed(); + } + + /* leak a pointer to the environment */ + buf = format("UNCACHED_ERR_FD=%d", uncached_fd); + + if (putenv(buf) == -1) { + cc_log("putenv failed: %s", strerror(errno)); + failed(); + } +} + +int +ccache_main(int argc, char *argv[]) +{ + char *p; + char *program_name; + + exitfn_init(); + exitfn_add_nullary(stats_flush); + exitfn_add_nullary(clean_up_tmp_files); + + /* check for logging early so cc_log messages start working ASAP */ + cache_logfile = getenv("CCACHE_LOGFILE"); + cc_log("=== CCACHE STARTED ========================================="); + + /* the user might have set CCACHE_UMASK */ + p = getenv("CCACHE_UMASK"); + if (p) { + mode_t mask; + errno = 0; + mask = strtol(p, NULL, 8); + if (errno == 0) { + umask(mask); + } + } + + current_working_dir = get_cwd(); + if (!current_working_dir) { + cc_log("Could not determine current working directory"); + failed(); + } + cache_dir = getenv("CCACHE_DIR"); + if (cache_dir) { + cache_dir = x_strdup(cache_dir); + } else { + const char *home_directory = get_home_directory(); + if (home_directory) { + cache_dir = format("%s/.ccache", home_directory); + } + } + + /* check if we are being invoked as "ccache" */ + program_name = basename(argv[0]); + if (same_executable_name(program_name, MYNAME)) { + if (argc < 2) { + fputs(USAGE_TEXT, stderr); + 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); + + check_cache_dir(); + + temp_dir = getenv("CCACHE_TEMPDIR"); + if (!temp_dir) { + temp_dir = format("%s/tmp", cache_dir); + } + + base_dir = getenv("CCACHE_BASEDIR"); + if (base_dir && base_dir[0] != '/') { + cc_log("Ignoring non-absolute base directory %s", base_dir); + base_dir = NULL; + } + + compile_preprocessed_source_code = !getenv("CCACHE_CPP2"); + + setup_uncached_err(); + + /* make sure the cache dir exists */ + if (create_dir(cache_dir) != 0) { + fprintf(stderr, + "ccache: failed to create %s (%s)\n", + cache_dir, strerror(errno)); + exit(1); + } + + /* make sure the temp dir exists */ + if (create_dir(temp_dir) != 0) { + fprintf(stderr, + "ccache: failed to create %s (%s)\n", + temp_dir, strerror(errno)); + exit(1); + } + + if (!getenv("CCACHE_READONLY")) { + if (create_cachedirtag(cache_dir) != 0) { + fprintf(stderr, + "ccache: failed to create %s/CACHEDIR.TAG (%s)\n", + cache_dir, strerror(errno)); + exit(1); + } + } + + ccache(argc, argv); + return 1; +} diff --git a/ccache.h b/ccache.h new file mode 100644 index 0000000..c2536f5 --- /dev/null +++ b/ccache.h @@ -0,0 +1,248 @@ +#ifndef CCACHE_H +#define CCACHE_H + +#include "system.h" +#include "mdfour.h" +#include "counters.h" + +#ifdef __GNUC__ +#define ATTR_FORMAT(x, y, z) __attribute__((format (x, y, z))) +#else +#define ATTR_FORMAT(x, y, z) +#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_MAXFILES = 13, + STATS_MAXSIZE = 14, + STATS_SOURCELANG = 15, + STATS_DEVICE = 16, + STATS_NOINPUT = 17, + STATS_MULTIPLE = 18, + STATS_CONFTEST = 19, + STATS_UNSUPPORTED = 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_END +}; + +#define SLOPPY_INCLUDE_FILE_MTIME 1 +#define SLOPPY_FILE_MACRO 2 +#define SLOPPY_TIME_MACROS 4 + +#define str_eq(s1, s2) (strcmp((s1), (s2)) == 0) +#define str_startswith(s, p) (strncmp((s), (p), strlen((p))) == 0) + +/* ------------------------------------------------------------------------- */ +/* 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_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_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_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_log_argv(const char *prefix, char **argv); +void fatal(const char *format, ...) ATTR_FORMAT(printf, 1, 2); + +void copy_fd(int fd_in, int fd_out); +int copy_file(const char *src, const char *dest, int compress_dest); +int move_file(const char *src, const char *dest, int compress_dest); +int move_uncompressed_file(const char *src, const char *dest, + int compress_dest); +bool file_is_compressed(const char *filename); + +int create_dir(const char *dir); +const char *get_hostname(void); +const char *tmp_string(void); +char *format_hash_as_string(const unsigned char *hash, unsigned size); +int create_hash_dir(char **dir, const char *hash, const char *cache_dir); +int create_cachedirtag(const char *dir); +char *format(const char *format, ...) ATTR_FORMAT(printf, 1, 2); +char *x_strdup(const char *s); +char *x_strndup(const char *s, size_t n); +void *x_realloc(void *ptr, size_t size); +void *x_malloc(size_t size); +void *x_calloc(size_t nmemb, size_t size); +void traverse(const char *dir, void (*fn)(const char *, struct stat *)); +char *basename(const char *s); +char *dirname(char *s); +const char *get_extension(const char *path); +char *remove_extension(const char *path); +size_t file_size(struct stat *st); +int safe_open(const char *fname); +char *x_realpath(const char *path); +char *gnu_getcwd(void); +int create_empty_file(const char *fname); +const char *get_home_directory(void); +char *get_cwd(); +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); +void update_mtime(const char *path); +int x_rename(const char *oldpath, const char *newpath); +int x_unlink(const char *path); +int tmp_unlink(const char *path); +char *x_readlink(const char *path); +char *read_text_file(const char *path); +bool read_file(const char *path, size_t size_hint, char **data, size_t *size); + +/* ------------------------------------------------------------------------- */ +/* 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(void); +void stats_update_size(enum stats stat, size_t size, unsigned files); +void stats_get_limits(const char *dir, unsigned *maxfiles, unsigned *maxsize); +int stats_set_limits(long maxfiles, long maxsize); +size_t value_units(const char *s); +char *format_size(size_t v); +void stats_set_sizes(const char *dir, size_t num_files, size_t total_size); +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(const char *dir, size_t maxfiles, size_t maxsize); +void cleanup_all(const char *dir); +void wipe_all(const char *dir); + +/* ------------------------------------------------------------------------- */ +/* execute.c */ + +int execute(char **argv, + const char *path_stdout, + const char *path_stderr); +char *find_executable(const char *name, const char *exclude_name); +void print_command(FILE *fp, char **argv); +void print_executed_command(FILE *fp, char **argv); + +/* ------------------------------------------------------------------------- */ +/* lockfile.c */ + +bool lockfile_acquire(const char *path, unsigned staleness_limit); +void lockfile_release(const char *path); + +/* ------------------------------------------------------------------------- */ +/* ccache.c */ + +bool cc_process_args(struct args *orig_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 +int win32execute(char *path, char **argv, int doreturn, + const char *path_stdout, const char *path_stderr); +# 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,NULL,NULL) +# define execute(a,b,c) win32execute(*(a),a,1,b,c) +# define PATH_DELIM ";" +# define F_RDLCK 0 +# define F_WRLCK 0 +#else +# define PATH_DELIM ":" +#endif + +#endif /* ifndef CCACHE_H */ diff --git a/cleanup.c b/cleanup.c new file mode 100644 index 0000000..530bd45 --- /dev/null +++ b/cleanup.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2002-2006 Andrew Tridgell + * Copyright (C) 2009-2010 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" + +/* + * 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. + */ +#define LIMIT_MULTIPLE 0.8 + +static struct files { + char *fname; + time_t mtime; + size_t size; /* In KiB. */ +} **files; +static unsigned allocated; /* Size of the files array. */ +static unsigned num_files; /* Number of used entries in the files array. */ + +static size_t cache_size; /* In KiB. */ +static size_t files_in_cache; +static size_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) +{ + char *p; + + if (!S_ISREG(st->st_mode)) return; + + 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; + } + + if (strstr(p, ".tmp.") != NULL) { + /* delete any tmp files older than 1 hour */ + if (st->st_mtime + 3600 < time(NULL)) { + x_unlink(fname); + 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) / 1024; + 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) { + 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; + + path = format("%s%s", base, extension); + if (lstat(path, &st) == 0) { + delete_file(path, file_size(&st) / 1024); + } else if (errno != ENOENT) { + 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 void +sort_and_clean(void) +{ + unsigned i; + const char *ext; + char *last_base = x_strdup(""); + + 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 */ + for (i = 0; i < num_files; i++) { + 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, ".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, ".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); + } + } + free(last_base); +} + +/* cleanup in one cache subdir */ +void +cleanup_dir(const char *dir, size_t maxfiles, size_t maxsize) +{ + unsigned i; + + cc_log("Cleaning up cache directory %s", dir); + + cache_size_threshold = maxsize * LIMIT_MULTIPLE; + files_in_cache_threshold = maxfiles * LIMIT_MULTIPLE; + + num_files = 0; + cache_size = 0; + files_in_cache = 0; + + /* build a list of files */ + traverse(dir, traverse_fn); + + /* clean the cache */ + sort_and_clean(); + + stats_set_sizes(dir, files_in_cache, cache_size); + + /* free it up */ + for (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; +} + +/* cleanup in all cache subdirs */ +void cleanup_all(const char *dir) +{ + unsigned maxfiles, maxsize; + char *dname; + int i; + + for (i = 0; i <= 0xF; i++) { + dname = format("%s/%1x", dir, i); + stats_get_limits(dname, &maxfiles, &maxsize); + cleanup_dir(dname, maxfiles, maxsize); + free(dname); + } +} + +/* traverse function for wiping files */ +static void wipe_fn(const char *fname, struct stat *st) +{ + char *p; + + if (!S_ISREG(st->st_mode)) return; + + p = basename(fname); + if (str_eq(p, "stats")) { + free(p); + return; + } + free(p); + + x_unlink(fname); +} + +/* wipe all cached files in all subdirs */ +void wipe_all(const char *dir) +{ + char *dname; + int i; + + for (i = 0; i <= 0xF; i++) { + dname = format("%s/%1x", dir, i); + traverse(dir, wipe_fn); + free(dname); + } + + /* and fix the counters */ + cleanup_all(dir); +} diff --git a/compopt.c b/compopt.c new file mode 100644 index 0000000..b2d0655 --- /dev/null +++ b/compopt.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2010 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[] = { + {"--coverage", TOO_HARD}, + {"--param", TAKES_ARG}, + {"-A", TAKES_ARG}, + {"-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}, + {"-U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG}, + {"-V", TAKES_ARG}, + {"-Xassembler", TAKES_ARG}, + {"-Xlinker", TAKES_ARG}, + {"-Xpreprocessor", TOO_HARD_DIRECT | TAKES_ARG}, + {"-aux-info", TAKES_ARG}, + {"-b", TAKES_ARG}, + {"-fbranch-probabilities", TOO_HARD}, + {"-fprofile-arcs", TOO_HARD}, + {"-fprofile-generate", TOO_HARD}, + {"-fprofile-use", TOO_HARD}, + {"-frepo", TOO_HARD}, + {"-ftest-coverage", TOO_HARD}, + {"-idirafter", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-iframework", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, + {"-imacros", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-imultilib", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-include", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-install_name", TAKES_ARG}, /* Darwin linker option */ + {"-iprefix", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-iquote", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-isysroot", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-isystem", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-iwithprefix", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-iwithprefixbefore", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, + {"-nostdinc", AFFECTS_CPP}, + {"-nostdinc++", AFFECTS_CPP}, + {"-save-temps", TOO_HARD}, + {"-u", TAKES_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 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); +} + +/* 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) +{ + size_t i; + for (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); +} diff --git a/compopt.h b/compopt.h new file mode 100644 index 0000000..8985ac3 --- /dev/null +++ b/compopt.h @@ -0,0 +1,13 @@ +#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); + +#endif /* CCACHE_COMPOPT_H */ diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..83c1e2a --- /dev/null +++ b/config.h.in @@ -0,0 +1,229 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* 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 `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 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 stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_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 `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 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 the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* 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 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 + +/* 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 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/configure b/configure new file mode 100755 index 0000000..d77051a --- /dev/null +++ b/configure @@ -0,0 +1,6881 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.67. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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. +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 + +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" + 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 : + # 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. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +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_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; } + + # 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 -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +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 + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# 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_deps +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 +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 +' + 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' +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 ;; + + -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 +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 + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + 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] + --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 +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +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.67 + +Copyright (C) 2010 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; test "x$as_lineno_stack" = x && { as_lineno=; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 || + $as_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; test "x$as_lineno_stack" = x && { as_lineno=; 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 "test \"\${$3+set}\"" = set; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 "test \"\${$3+set}\"" = set; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 "test \"\${$3+set}\"" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval "test \"\${$3+set}\"" = set; 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 "test \"\${$3+set}\"" = set; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 "test \"\${$3+set}\"" = set; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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 "test \"\${$4+set}\"" = set; 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; test "x$as_lineno_stack" = x && { as_lineno=; 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.67. 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_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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_ac_ct_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_ac_ct_CC+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_objext+set}" = set; 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 test "${ac_cv_c_compiler_gnu+set}" = set; 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 test "${ac_cv_prog_cc_g+set}" = set; 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 test "${ac_cv_prog_cc_c89+set}" = set; 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> +#include <sys/types.h> +#include <sys/stat.h> +/* 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 + +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 test "${ac_cv_prog_CPP+set}" = set; 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 + +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. + + +# 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 test "${ac_cv_path_install+set}" = set; 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 { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_RANLIB+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_AR+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 test "${ac_cv_prog_ac_ct_AR+set}" = set; 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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 + + +# 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) + 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) + ;; + *) + +$as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h + + ;; + esac + + +$as_echo "#define _POSIX_C_SOURCE 200112L" >>confdefs.h + + +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 "test \"\${$as_ac_Header+set}\"" = set; 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 test "${ac_cv_search_opendir+set}" = set; 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 test "${ac_cv_search_opendir+set}" = set; then : + break +fi +done +if test "${ac_cv_search_opendir+set}" = set; 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 test "${ac_cv_search_opendir+set}" = set; 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 test "${ac_cv_search_opendir+set}" = set; then : + break +fi +done +if test "${ac_cv_search_opendir+set}" = set; 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 test "${ac_cv_header_time+set}" = set; 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 grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; 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" + { test -f "$ac_path_GREP" && $as_test_x "$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 test "${ac_cv_path_EGREP+set}" = set; 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" + { test -f "$ac_path_EGREP" && $as_test_x "$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 test "${ac_cv_header_stdc+set}" = set; 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 + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 +$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } +if test "${ac_cv_header_stdbool_h+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include <stdbool.h> +#ifndef bool + "error: bool is not defined" +#endif +#ifndef false + "error: false is not defined" +#endif +#if false + "error: false is not 0" +#endif +#ifndef true + "error: true is not defined" +#endif +#if true != 1 + "error: true is not 1" +#endif +#ifndef __bool_true_false_are_defined + "error: __bool_true_false_are_defined is not defined" +#endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) 0.5 == true ? 1 : -1]; + bool e = &s; + char f[(_Bool) 0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + enum { j = false, k = true, l = false * true, m = true * 256 }; + /* The following fails for + HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ + _Bool n[m]; + char o[sizeof n == m * sizeof n[0] ? 1 : -1]; + char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; +# if defined __xlc__ || defined __GNUC__ + /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0 + reported by James Lemley on 2005-10-05; see + http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html + This test is not quite right, since xlc is allowed to + reject this program, as the initializer for xlcbug is + not one of the forms that C requires support for. + However, doing the test right would require a runtime + test, and that would make cross-compilation harder. + Let us hope that IBM fixes the xlc bug, and also adds + support for this kind of constant expression. In the + meantime, this test will reject xlc, which is OK, since + our stdbool.h substitute should suffice. We also test + this with GCC, where it should work, to detect more + quickly whether someone messes up the test in the + future. */ + char digs[] = "0123456789"; + int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1); +# endif + /* Catch a bug in an HP-UX C compiler. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + */ + _Bool q = true; + _Bool *pq = &q; + +int +main () +{ + + *pq |= q; + *pq |= ! q; + /* Refer to every declared value, to avoid compiler optimizations. */ + return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + + !m + !n + !o + !p + !q + !pq); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdbool_h=yes +else + ac_cv_header_stdbool_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_stdbool_h" >&5 +$as_echo "$ac_cv_header_stdbool_h" >&6; } +ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" +if test "x$ac_cv_type__Bool" = x""yes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 +_ACEOF + + +fi + +if test $ac_cv_header_stdbool_h = yes; then + +$as_echo "#define HAVE_STDBOOL_H 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 test "${ac_cv_header_sys_wait_h+set}" = set; 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 + + +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" = x""yes; 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" = x""yes; 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" = x""yes; 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" = x""yes; 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" = x""yes; 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" = x""yes; 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" = x""yes; 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" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRNDUP 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" = x""yes; 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 test "${ccache_cv_COMPAR_FN_T+set}" = set; 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 + + + + + + + + ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" +if test "x$ac_cv_func_vsnprintf" = x""yes; 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 test "${hw_cv_func_vsnprintf_c99+set}" = set; 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" = x""yes; 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" = x""yes; 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 test "${ac_cv_type_long_long_int+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + 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 : + if test "$cross_compiling" = yes; then : + ac_cv_type_long_long_int=yes +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 : + ac_cv_type_long_long_int=yes +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 + +else + ac_cv_type_long_long_int=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +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 test "${ac_cv_type_unsigned_long_long_int+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + 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 : + ac_cv_type_unsigned_long_long_int=yes +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 +{ $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" = x""yes; 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" = x""yes; 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" = x""yes; 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" = x""yes; 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 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" = x""yes; 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" = x""yes; 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 test "${ac_cv_c_const+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* 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. */ + char *t; + 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 saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; 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" = x""yes; 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 test "${hw_cv_func_snprintf_c99+set}" = set; 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 test "${ac_cv_c_const+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* 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. */ + char *t; + 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 saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; 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" = x""yes; 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" = x""yes; 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 test "${hw_cv_func_va_copy+set}" = set; 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 test "${hw_cv_func___va_copy+set}" = set; 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 test "${ac_cv_c_const+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* 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. */ + char *t; + 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 saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; 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" = x""yes; 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 test "${ac_cv_c_const+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* 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. */ + char *t; + 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 saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; 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 test "${ac_cv_search_cos+set}" = set; 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 test "${ac_cv_search_cos+set}" = set; then : + break +fi +done +if test "${ac_cv_search_cos+set}" = set; 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 + + +{ $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 test "${ccache_cv_zlib_1_2_3+set}" = set; 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 test "${ac_cv_lib_z_gzdopen+set}" = set; 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" = x""yes; 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 + use_bundled_zlib=yes + extra_deps="zlib/libz.a" + CPPFLAGS="$CPPFLAGS -I\$(srcdir)/zlib" + LIBS="-Lzlib $LIBS" + mkdir -p zlib +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if test "${ac_cv_c_inline+set}" = set; 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 test "${ac_cv_c_extern_inline+set}" = set; 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.mk.in && test "$RUN_FROM_BUILD_FARM" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Enabling developer mode" >&5 +$as_echo "$as_me: Enabling developer mode" >&6;} + ac_config_files="$ac_config_files dev.mk" + + include_dev_mk='include dev.mk' + version=`(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 +elif 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="" +for x in $srcdir/test/test_*.c; do + test_suites="$test_suites $x" +done + +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 + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + 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. +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 -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +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 + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# 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.67. 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.67, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 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= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$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 -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 + +# 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 {' >"$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 >>"\$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 >>"\$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 < "$tmp/subs1.awk" > "$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 >"$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_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; 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="$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 >"$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 "$tmp/subs.awk" >$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' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$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 "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$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 "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$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 "$tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$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 + +if test x$use_bundled_zlib = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using bundled zlib" >&5 +$as_echo "$as_me: WARNING: using bundled zlib" >&2;} +fi + +{ $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/counters.c b/counters.c new file mode 100644 index 0000000..4e3036a --- /dev/null +++ b/counters.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 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 struct counters. + */ +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) { + size_t i; + 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 (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..4552379 --- /dev/null +++ b/counters.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 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 + +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/execute.c b/execute.c new file mode 100644 index 0000000..80e327e --- /dev/null +++ b/execute.c @@ -0,0 +1,310 @@ +/* + * Copyright (C) Andrew Tridgell 2002 + * Copyright (C) Joel Rosdahl 2011 + * + * 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 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 + */ +static char * +argvtos(char *prefix, char **argv) +{ + char *arg; + char *ptr; + char *str; + int l = 0; + int i, j; + + i = 0; + arg = prefix ? prefix : argv[i++]; + do { + int bs = 0; + for (j = 0; arg[j]; j++) { + switch (arg[j]) { + case '\\': + bs++; + break; + case '"': + bs = (bs << 1) + 1; + default: + l += bs + 1; + bs = 0; + } + } + l += (bs << 1) + 3; + } while ((arg = argv[i++])); + + str = ptr = malloc(l + 1); + if (str == NULL) + return NULL; + + i = 0; + arg = prefix ? prefix : argv[i++]; + do { + int bs = 0; + *ptr++ = '"'; + for (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++ = ' '; + } while ((arg = argv[i++])); + ptr[-1] = '\0'; + + return str; +} + +int +win32execute(char *path, char **argv, int doreturn, + const char *path_stdout, const char *path_stderr) +{ + PROCESS_INFORMATION pi; + STARTUPINFO si; + BOOL ret; + DWORD exitcode; + char *path_env; + char *sh = NULL; + char *args; + const char *ext; + + memset(&pi, 0x00, sizeof(pi)); + memset(&si, 0x00, sizeof(si)); + + 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; + 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); + } + } + if (sh) + path = sh; + + si.cb = sizeof(STARTUPINFO); + if (path_stdout) { + SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + si.hStdOutput = CreateFile(path_stdout, GENERIC_WRITE, 0, &sa, + CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | + FILE_FLAG_SEQUENTIAL_SCAN, NULL); + si.hStdError = CreateFile(path_stderr, GENERIC_WRITE, 0, &sa, + CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | + FILE_FLAG_SEQUENTIAL_SCAN, NULL); + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.dwFlags = STARTF_USESTDHANDLES; + if (si.hStdOutput == INVALID_HANDLE_VALUE || + si.hStdError == INVALID_HANDLE_VALUE) + return -1; + } + args = argvtos(sh, argv); + ret = CreateProcess(path, args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi); + free(args); + if (path_stdout) { + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + } + if (ret == 0) + return -1; + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &exitcode); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + if (!doreturn) + 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, const char *path_stdout, const char *path_stderr) +{ + pid_t pid; + int status; + + cc_log_argv("Executing ", argv); + + pid = fork(); + if (pid == -1) fatal("Failed to fork: %s", strerror(errno)); + + if (pid == 0) { + int fd; + + tmp_unlink(path_stdout); + fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666); + if (fd == -1) { + exit(1); + } + dup2(fd, 1); + close(fd); + + tmp_unlink(path_stderr); + fd = open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666); + if (fd == -1) { + exit(1); + } + dup2(fd, 2); + close(fd); + + exit(execv(argv[0], argv)); + } + + if (waitpid(pid, &status, 0) != pid) { + fatal("waitpid failed: %s", strerror(errno)); + } + + 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) +{ + char *path; + + if (is_absolute_path(name)) { + return x_strdup(name); + } + + path = getenv("CCACHE_PATH"); + if (!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) +{ + char *tok, *saveptr = NULL; + + path = x_strdup(path); + + /* search the path looking for the first compiler of the right name + that isn't us */ + for (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, ".exe", + sizeof(namebuf), namebuf, NULL); + if (!ret) + ret = SearchPath(tok, name, NULL, + sizeof(namebuf), namebuf, NULL); + (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) +{ + int i; + for (i = 0; argv[i]; i++) { + fprintf(fp, "%s%s", (i == 0) ? "" : " ", argv[i]); + } + fprintf(fp, "\n"); +} + +void +print_executed_command(FILE *fp, char **argv) +{ + fprintf(fp, "%s: executing ", MYNAME); + print_command(fp, argv); +} diff --git a/exitfn.c b/exitfn.c new file mode 100644 index 0000000..1393f3d --- /dev/null +++ b/exitfn.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010 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 context 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; + + 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, *q; + while (p) { + p->function(p->context); + q = p; + p = p->next; + free(q); + } + exit_functions = NULL; +} 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 */ @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2002 Andrew Tridgell + * Copyright (C) 2010 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], sum2[16]; + hash_result_as_bytes(md1, sum1); + 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_buffer(md, s, strlen(s)); +} + +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[16384]; + 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; + bool ret; + + fd = open(fname, O_RDONLY|O_BINARY); + if (fd == -1) { + return false; + } + + ret = hash_fd(md, fd); + close(fd); + return ret; +} diff --git a/hashtable.c b/hashtable.c new file mode 100644 index 0000000..68d34e8 --- /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 accomodate more entries */ + struct entry **newtable; + struct entry *e; + struct entry **pE; + 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 + { + 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..d935c5f --- /dev/null +++ b/hashutil.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2009-2010 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 "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; +} + +#define HASH(ch) \ + do {\ + hashbuf[hashbuflen] = ch; \ + hashbuflen++; \ + if (hashbuflen == sizeof(hashbuf)) {\ + hash_buffer(hash, hashbuf, sizeof(hashbuf)); \ + hashbuflen = 0; \ + } \ + } while (0) + +/* + * Hash a string ignoring comments. Returns a bitmask of HASH_SOURCE_CODE_* + * results. + */ +int +hash_source_code_string( + struct mdfour *hash, const char *str, size_t len, const char *path) +{ + const char *p; + const char *end; + char hashbuf[64]; + size_t hashbuflen = 0; + int result = HASH_SOURCE_CODE_OK; + extern unsigned sloppiness; + + p = str; + end = str + len; + while (1) { + if (p >= end) { + goto end; + } + switch (*p) { + /* Potential start of comment. */ + case '/': + if (p+1 == end) { + break; + } + switch (*(p+1)) { + case '*': + HASH(' '); /* Don't paste tokens together when removing the comment. */ + p += 2; + while (p+1 < end + && (*p != '*' || *(p+1) != '/')) { + if (*p == '\n') { + /* Keep line numbers. */ + HASH('\n'); + } + p++; + } + if (p+1 == end) { + goto end; + } + p += 2; + continue; + + case '/': + p += 2; + while (p < end + && (*p != '\n' || *(p-1) == '\\')) { + p++; + } + continue; + + default: + break; + } + break; + + /* Start of string. */ + case '"': + HASH(*p); + p++; + while (p < end && (*p != '"' || *(p-1) == '\\')) { + HASH(*p); + p++; + } + if (p == end) { + goto end; + } + break; + + /* Potential start of volatile macro. */ + case '_': + if (p + 7 < end + && p[1] == '_' && p[5] == 'E' + && p[6] == '_' && p[7] == '_') { + if (p[2] == 'D' && p[3] == 'A' + && p[4] == 'T') { + result |= HASH_SOURCE_CODE_FOUND_DATE; + } else if (p[2] == 'T' && p[3] == 'I' + && p[4] == 'M') { + result |= HASH_SOURCE_CODE_FOUND_TIME; + } + /* + * Of course, we can't be sure that we have found a __{DATE,TIME}__ + * that's actually used, but better safe than sorry. And if you do + * something like + * + * #define TIME __TI ## ME__ + * + * in your code, you deserve to get a false cache hit. + */ + } + break; + + default: + break; + } + + HASH(*p); + p++; + } + +end: + hash_buffer(hash, hashbuf, hashbuflen); + + if (sloppiness & SLOPPY_TIME_MACROS) { + return 0; + } + 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 mdfour *hash, const char *path) +{ + char *data; + size_t size; + int result; + + if (is_precompiled_header(path)) { + if (hash_file(hash, path)) { + return HASH_SOURCE_CODE_OK; + } else { + return HASH_SOURCE_CODE_ERROR; + } + } else { + if (!read_file(path, 0, &data, &size)) { + return HASH_SOURCE_CODE_ERROR; + } + result = hash_source_code_string(hash, data, size, path); + free(data); + return result; + } +} + +bool +hash_command_output(struct mdfour *hash, const char *command, + const char *compiler) +{ + pid_t pid; + int pipefd[2]; + + struct args *args = args_init_from_string(command); + int i; + for (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); + + if (pipe(pipefd) == -1) { + fatal("pipe failed"); + } + 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. */ + int status; + bool ok; + args_free(args); + close(pipefd[1]); + 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]); + 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; + } +} + +bool +hash_multicommand_output(struct mdfour *hash, const char *commands, + const char *compiler) +{ + char *command_string, *command, *p, *saveptr = NULL; + bool ok = true; + + command_string = x_strdup(commands); + p = command_string; + 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..a897b3e --- /dev/null +++ b/hashutil.h @@ -0,0 +1,31 @@ +#ifndef HASHUTIL_H +#define HASHUTIL_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 hash_source_code_string( + struct mdfour *hash, const char *str, size_t len, const char *path); +int hash_source_code_file(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..acbeb89 --- /dev/null +++ b/language.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2010 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++"}, + /* Preprocessed: */ + {".i", "cpp-output"}, + {".ii", "c++-cpp-output"}, + {".mi", "objc-cpp-output"}, + {".mii", "objc++-cpp-output"}, + /* 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"}, + {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", "objc-cpp-output"}, + {"objective-c-header", "objc-cpp-output"}, + {"objc-cpp-output", "objc-cpp-output"}, + {"objective-c++", "objc++-cpp-output"}, + {"objc++-cpp-output", "objc++-cpp-output"}, + {"objective-c++-header", "objc++-cpp-output"}, + {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) +{ + int i; + const char *p; + + p = get_extension(fname); + for (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) +{ + int i; + + if (!language) { + return NULL; + } + for (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) +{ + int i; + + if (!language) { + return NULL; + } + for (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..6f674d1 --- /dev/null +++ b/language.h @@ -0,0 +1,10 @@ +#ifndef CCACHE_LANGUAGE_H +#define CCACHE_LANGUAGE_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..84144a3 --- /dev/null +++ b/lockfile.c @@ -0,0 +1,212 @@ +/* + * 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" + +/* + * 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, *content = NULL, *initial_content = NULL; + const char *hostname = get_hostname(); + bool acquired = false; +#ifdef _WIN32 + const size_t bufsize = 1024; + int fd, len; +#else + int ret; +#endif + unsigned to_sleep = 1000, slept = 0; /* Microseconds. */ + + while (1) { + free(my_content); + my_content = format("%s:%d:%d", hostname, (int)getpid(), (int)time(NULL)); + +#ifdef _WIN32 + fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666); + if (fd == -1) { + cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno)); + if (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); + content = x_malloc(bufsize); + if ((len = read(fd, content, bufsize - 1)) == -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 + ret = symlink(my_content, lockfile); + if (ret == 0) { + /* We got the lock. */ + acquired = true; + goto out; + } + cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(errno)); + if (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 (errno != EEXIST) { + /* Directory doesn't exist or isn't writable? */ + goto out; + } + free(content); + content = x_readlink(lockfile); + 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); + if (lockfile_acquire(lockfile, staleness_limit)) { + lockfile_release(path); + lockfile_release(lockfile); + 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 @@ -0,0 +1,28 @@ +/* + * ccache -- a fast C/C++ compiler cache + * + * Copyright (C) 2010 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..fcc163d --- /dev/null +++ b/manifest.c @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2009-2010 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) + * ... + * <hash[n-1]> + * <size[n-1]> + * <index[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 uint8_t VERSION = 0; +static const uint32_t MAX_MANIFEST_ENTRIES = 100; + +#define static_assert(e) do { enum { static_assert__ = 1/(e) }; } while (0) + +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; +}; + +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 { + /* 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; +}; + +static unsigned int +hash_from_file_info(void *key) +{ + static_assert(sizeof(struct file_info) == 24); /* 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; +} + +static void +free_manifest(struct manifest *mf) +{ + uint16_t i; + for (i = 0; i < mf->n_files; i++) { + free(mf->files[i]); + } + free(mf->files); + free(mf->file_infos); + for (i = 0; i < mf->n_objects; i++) { + free(mf->objects[i].file_info_indexes); + } + free(mf->objects); +} + +#define READ_INT(size, var) \ + do { \ + int ch_; \ + size_t i_; \ + (var) = 0; \ + for (i_ = 0; i_ < (size); i_++) { \ + ch_ = gzgetc(f); \ + if (ch_ == EOF) { \ + goto error; \ + } \ + (var) <<= 8; \ + (var) |= ch_ & 0xFF; \ + } \ + } while (0) + +#define READ_STR(var) \ + do { \ + char buf_[1024]; \ + size_t i_; \ + int ch_; \ + for (i_ = 0; i_ < sizeof(buf_); i_++) { \ + 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 (0) + +#define READ_BYTES(n, var) \ + do { \ + size_t i_; \ + int ch_; \ + for (i_ = 0; i_ < (n); i_++) { \ + ch_ = gzgetc(f); \ + if (ch_ == EOF) { \ + goto error; \ + } \ + (var)[i_] = ch_; \ + } \ + } while (0) + +static struct manifest * +create_empty_manifest(void) +{ + struct manifest *mf; + + 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; + uint16_t i, j; + uint32_t magic; + uint8_t version; + uint16_t dummy; + + mf = create_empty_manifest(); + + READ_INT(4, magic); + if (magic != MAGIC) { + cc_log("Manifest file has bad magic number %u", magic); + free_manifest(mf); + return NULL; + } + READ_INT(1, version); + if (version != VERSION) { + cc_log("Manifest file has unknown version %u", version); + free_manifest(mf); + return NULL; + } + + READ_INT(1, 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); + free_manifest(mf); + return NULL; + } + + READ_INT(2, dummy); + + READ_INT(4, mf->n_files); + mf->files = x_calloc(mf->n_files, sizeof(*mf->files)); + for (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 (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(4, mf->n_objects); + mf->objects = x_calloc(mf->n_objects, sizeof(*mf->objects)); + for (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 (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 { \ + uint8_t ch_; \ + size_t i_; \ + for (i_ = 0; i_ < (size); i_++) { \ + ch_ = ((var) >> (8 * ((size) - i_ - 1))); \ + if (gzputc(f, ch_) == EOF) { \ + goto error; \ + } \ + } \ + } while (0) + +#define WRITE_STR(var) \ + do { \ + if (gzputs(f, var) == EOF || gzputc(f, '\0') == EOF) { \ + goto error; \ + } \ + } while (0) + +#define WRITE_BYTES(n, var) \ + do { \ + size_t i_; \ + for (i_ = 0; i_ < (n); i_++) { \ + if (gzputc(f, (var)[i_]) == EOF) { \ + goto error; \ + } \ + } \ + } while (0) + +static int +write_manifest(gzFile f, const struct manifest *mf) +{ + uint16_t i, j; + + WRITE_INT(4, MAGIC); + WRITE_INT(1, VERSION); + WRITE_INT(1, 16); + WRITE_INT(2, 0); + + WRITE_INT(4, mf->n_files); + for (i = 0; i < mf->n_files; i++) { + WRITE_STR(mf->files[i]); + } + + WRITE_INT(4, mf->n_file_infos); + for (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(4, mf->n_objects); + for (i = 0; i < mf->n_objects; i++) { + WRITE_INT(4, mf->objects[i].n_file_info_indexes); + for (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 manifest *mf, struct object *obj, + struct hashtable *hashed_files) +{ + uint32_t i; + struct file_info *fi; + struct file_hash *actual; + struct mdfour hash; + int result; + + for (i = 0; i < obj->n_file_info_indexes; i++) { + fi = &mf->file_infos[obj->file_info_indexes[i]]; + actual = hashtable_search(hashed_files, mf->files[fi->index]); + if (!actual) { + actual = x_malloc(sizeof(*actual)); + hash_start(&hash); + result = hash_source_code_file(&hash, mf->files[fi->index]); + if (result & HASH_SOURCE_CODE_ERROR) { + cc_log("Failed hashing %s", mf->files[fi->index]); + free(actual); + return 0; + } + if (result & HASH_SOURCE_CODE_FOUND_TIME) { + free(actual); + return 0; + } + hash_result_as_bytes(&hash, actual->hash); + actual->size = hash.totalN; + hashtable_insert(hashed_files, x_strdup(mf->files[fi->index]), 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) +{ + uint32_t i; + struct hashtable *h; + uint32_t *index; + + h = create_hashtable(1000, hash_from_string, strings_equal); + for (i = 0; i < len; i++) { + 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) +{ + uint32_t i; + struct hashtable *h; + struct file_info *fi; + uint32_t *index; + + h = create_hashtable(1000, hash_from_file_info, file_infos_equal); + for (i = 0; i < len; i++) { + fi = x_malloc(sizeof(*fi)); + *fi = infos[i]; + 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; + uint32_t n; + + index = hashtable_search(mf_files, path); + if (index) { + return *index; + } + + 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; + uint32_t *fi_index; + uint32_t n; + + fi.index = get_include_file_index(mf, path, mf_files); + memcpy(fi.hash, file_hash->hash, sizeof(fi.hash)); + fi.size = file_hash->size; + + fi_index = hashtable_search(mf_file_infos, &fi); + if (fi_index) { + return *fi_index; + } + + 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) +{ + struct hashtable_itr *iter; + uint32_t i; + char *path; + struct file_hash *file_hash; + struct hashtable *mf_files; /* path --> index */ + struct hashtable *mf_file_infos; /* struct file_info --> index */ + + if (size == 0) { + return; + } + + mf_files = create_string_index_map(mf->files, mf->n_files); + mf_file_infos = create_file_info_index_map(mf->file_infos, mf->n_file_infos); + iter = hashtable_iterator(included_files); + i = 0; + do { + path = hashtable_iterator_key(iter); + 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) +{ + struct object *obj; + uint32_t n; + + n = mf->n_objects; + mf->objects = x_realloc(mf->objects, (n + 1) * sizeof(*mf->objects)); + mf->n_objects++; + obj = &mf->objects[n]; + + n = hashtable_count(included_files); + obj->n_file_info_indexes = n; + obj->file_info_indexes = x_malloc(n * sizeof(*obj->file_info_indexes)); + add_file_info_indexes(obj->file_info_indexes, n, 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(const char *manifest_path) +{ + int fd; + gzFile f = NULL; + struct manifest *mf = NULL; + struct hashtable *hashed_files = NULL; /* path --> struct file_hash */ + uint32_t i; + struct file_hash *fh = NULL; + + 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); + + /* Check newest object first since it's a bit more likely to match. */ + for (i = mf->n_objects; i > 0; i--) { + if (verify_object(mf, &mf->objects[i - 1], 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 (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; + int fd1; + int fd2; + 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. + */ + + 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(); + } + + tmp_file = format("%s.tmp.%s", manifest_path, tmp_string()); + fd2 = safe_open(tmp_file); + if (fd2 == -1) { + cc_log("Failed to open %s", tmp_file); + goto out; + } + 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; +} diff --git a/manifest.h b/manifest.h new file mode 100644 index 0000000..80333e7 --- /dev/null +++ b/manifest.h @@ -0,0 +1,11 @@ +#ifndef MANIFEST_H +#define MANIFEST_H + +#include "hashutil.h" +#include "hashtable.h" + +struct file_hash *manifest_get(const char *manifest_path); +bool manifest_put(const char *manifest_path, struct file_hash *object_hash, + struct hashtable *included_files); + +#endif diff --git a/mdfour.c b/mdfour.c new file mode 100644 index 0000000..6547dc0 --- /dev/null +++ b/mdfour.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 1997-1998 Andrew Tridgell + * + * 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., 675 Mass Ave, Cambridge, MA 02139, 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) +{ + int i; + + for (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); +} + +static void +copy4(unsigned char *out, uint32_t x) +{ + out[0] = x&0xFF; + out[1] = (x>>8)&0xFF; + out[2] = (x>>16)&0xFF; + out[3] = (x>>24)&0xFF; +} + +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) +{ + unsigned char buf[128] = { 0 }; + uint32_t M[16]; + uint32_t b; + + m->totalN += n; + + b = m->totalN * 8; + + 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) +{ + uint32_t M[16]; + +#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 == NULL) { + if (!md->finalized) { + mdfour_tail(md->tail, md->tail_len); + md->finalized = 1; + } + return; + } + + 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..e625ba8 --- /dev/null +++ b/murmurhashneutral2.c @@ -0,0 +1,50 @@ +/* + * 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; + + k = data[0]; + k |= data[1] << 8; + k |= data[2] << 16; + k |= data[3] << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + switch (len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= 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/packaging/ccache.changes b/packaging/ccache.changes new file mode 100644 index 0000000..7a20353 --- /dev/null +++ b/packaging/ccache.changes @@ -0,0 +1,192 @@ +------------------------------------------------------------------- +Sun Aug 21 18:24:58 UTC 2011 - asterios.dramis@gmail.com + +- update to ccache-3.1.6 + - Rewrite argument to --sysroot if CCACHE_BASEDIR is used. + - Don't crash if getcwd() fails. + - Fixed alignment of "called for preprocessing" counter. + +------------------------------------------------------------------- +Mon Jun 6 14:52:55 UTC 2011 - puzel@novell.com + +- update to ccache-3.1.5 + - 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. + - The `-MF`/`-MT`/`-MQ` options with concatenated argument are + now handled correctly when they are last on the commandline. + - 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. + +------------------------------------------------------------------- +Wed Feb 16 18:19:41 UTC 2011 - asterios.dramis@gmail.com + +- update to ccache-3.1.4 + - 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. +- Spec file updates: + - Changes based on rpmdevtools templates and spec-cleaner run. + - Updated Summary: and %description. + - Made it compile with external zlib instead of the bundled copy. + - Added also the html files in the %doc section. + +------------------------------------------------------------------- +Mon Nov 29 09:56:02 UTC 2010 - puzel@novell.com + +- update to ccache-3.1.3 + - The -MFarg, -MTarg and -MQarg compiler options (i.e, without + space between option and argument) are now handled correctly. + +------------------------------------------------------------------- +Mon Nov 22 10:58:50 UTC 2010 - puzel@novell.com + +- update to ccache-3.1.2 + - bail out on too hard compiler options '-fdump-*' + - NULL return values from malloc/calloc of zero bytes are now + handled correctly + - 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 + +------------------------------------------------------------------- +Mon Nov 8 09:46:57 UTC 2010 - puzel@novell.com + +- update to ccache-3.1.1 + - 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`. + +------------------------------------------------------------------- +Fri Sep 17 09:22:59 UTC 2010 - puzel@novell.com + +- update to ccache-3.1 + - features: + - 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. + - Added support for caching compilations that use precompiled + headers. + - Locking of the files containing statistics counters is now + done using symlinks instead of POSIX locks. + - Manifest files are now updated without the need of taking + locks. + - Added `.cp` and `.CP` as known C++ suffixes. + - Improved logging. + - bugfixes: + - 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. + +------------------------------------------------------------------- +Fri Jul 16 08:15:51 UTC 2010 - puzel@novell.com + +- update to ccache-3.0.1 + - bugfixes: + - 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. + +------------------------------------------------------------------- +Mon Jul 12 11:43:54 UTC 2010 - puzel@novell.com + +- update to ccache-3.0 + - notable changes: + - 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. + - 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. +- see /usr/share/doc/packages/ccache/NEWS.txt for complete + release notes + +------------------------------------------------------------------- +Wed Jan 25 21:34:51 CET 2006 - mls@suse.de + +- converted neededforbuild to BuildRequires + +------------------------------------------------------------------- +Thu Sep 29 03:16:43 CEST 2005 - dmueller@suse.de + + - add norootforbuild + +------------------------------------------------------------------- +Wed Sep 28 23:24:29 CEST 2005 - dmueller@suse.de + +- add norootforbuild + +------------------------------------------------------------------- +Thu Oct 21 11:56:47 CEST 2004 - ltinkl@suse.cz + +- update to version 2.4 + +------------------------------------------------------------------- +Mon Sep 29 11:38:06 CEST 2003 - ltinkl@suse.cz + +- update to version 2.3 + +------------------------------------------------------------------- +Wed Jul 09 13:28:43 CEST 2003 - ltinkl@suse.cz + +- updated sources to version 2.2 + +------------------------------------------------------------------- +Fri Mar 28 15:38:13 CET 2003 - vbobek@suse.cz + +- provides binary from older distcc package [#25806] + +------------------------------------------------------------------- +Mon Feb 10 14:32:44 CET 2003 - vbobek@suse.cz + +- initial suse release 2.1.1 + diff --git a/packaging/ccache.spec b/packaging/ccache.spec new file mode 100644 index 0000000..6e6086f --- /dev/null +++ b/packaging/ccache.spec @@ -0,0 +1,59 @@ +# +# spec file for package ccache +# +# Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +# norootforbuild + + +Name: ccache +Version: 3.1.6 +Release: 1 +Summary: A Fast C/C++ Compiler Cache + +License: GPLv3+ +Url: http://ccache.samba.org/ +Group: Development/Languages/C and C++ +Source0: http://samba.org/ftp/ccache/%{name}-%{version}.tar.bz2 +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +BuildRequires: zlib-devel +Provides: distcc:/usr/bin/ccache + +%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++. + +%prep +%setup -q + +%build +%configure +make %{?_smp_mflags} + +%install +make install DESTDIR=%{buildroot} + +%clean +rm -rf %{buildroot} + +%files +%defattr(-,root,root,-) +%doc AUTHORS.* GPL-3.0.txt INSTALL.* LICENSE.* MANUAL.* NEWS.* README.* +%doc %{_mandir}/man1/ccache.1%{ext_man} +%{_bindir}/ccache + +%changelog diff --git a/snprintf.c b/snprintf.c new file mode 100644 index 0000000..e1b86f2 --- /dev/null +++ b/snprintf.c @@ -0,0 +1,2114 @@ +/* $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); + +extern int errno; + +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: */ @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2002-2004 Andrew Tridgell + * Copyright (C) 2009-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 + */ + +/* + * 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 char *cache_dir; +extern unsigned lock_staleness_limit; + +static struct counters *counter_updates; + +/* default maximum cache size */ +#ifndef DEFAULT_MAXSIZE +#define DEFAULT_MAXSIZE (1024*1024) +#endif + +#define FLAG_NOZERO 1 /* don't zero with the -z option */ +#define FLAG_ALWAYS 2 /* always show, even if zero */ + +static void display_size(size_t v); + +/* statistics fields in display order */ +static struct { + enum stats stat; + char *message; + void (*fn)(size_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, "unsupported compiler option ", 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_NUMFILES, "files in cache ", NULL, FLAG_NOZERO|FLAG_ALWAYS }, + { STATS_TOTALSIZE, "cache size ", display_size , FLAG_NOZERO|FLAG_ALWAYS }, + { STATS_MAXFILES, "max files ", NULL, FLAG_NOZERO }, + { STATS_MAXSIZE, "max cache size ", display_size, FLAG_NOZERO }, + { STATS_NONE, NULL, NULL, 0 } +}; + +static void +display_size(size_t v) +{ + char *s = format_size(v); + printf("%15s", s); + free(s); +} + +/* 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; + char *p2; + long val; + + p = buf; + while (1) { + 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) +{ + size_t i; + char *tmp_file; + FILE *f; + + tmp_file = format("%s.tmp.%s", path, tmp_string()); + f = fopen(tmp_file, "wb"); + if (!f) { + cc_log("Failed to open %s", tmp_file); + goto end; + } + for (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); + +end: + free(tmp_file); +} + +/* fill in some default stats values */ +static void +stats_default(struct counters *counters) +{ + counters->data[STATS_MAXSIZE] += DEFAULT_MAXSIZE / 16; +} + +static void +init_counter_updates(void) +{ + if (!counter_updates) { + counter_updates = counters_init(STATS_END); + } +} + +/* + * Update a statistics counter (unless it's STATS_NONE) and also record that a + * number of bytes and files have been added to the cache. Size is in KiB. + */ +void +stats_update_size(enum stats stat, size_t size, unsigned files) +{ + init_counter_updates(); + if (stat != STATS_NONE) { + counter_updates->data[stat]++; + } + counter_updates->data[STATS_NUMFILES] += files; + counter_updates->data[STATS_TOTALSIZE] += size; +} + +/* 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); + if (data) { + parse_stats(counters, data); + } else { + stats_default(counters); + } + free(data); +} + +/* + * Write counter updates in counter_updates to disk. + */ +void +stats_flush(void) +{ + struct counters *counters; + bool need_cleanup = false; + bool should_flush = false; + int i; + extern char *cache_logfile; + + if (getenv("CCACHE_NOSTATS")) return; + + init_counter_updates(); + + for (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. + */ + if (!cache_dir) return; + stats_dir = format("%s/%x", cache_dir, hash_from_int(getpid()) % 16); + stats_file = format("%s/stats", stats_dir); + create_dir(stats_dir); + free(stats_dir); + } + + if (!lockfile_acquire(stats_file, lock_staleness_limit)) { + return; + } + counters = counters_init(STATS_END); + stats_read(stats_file, counters); + for (i = 0; i < STATS_END; ++i) { + counters->data[i] += counter_updates->data[i]; + } + stats_write(stats_file, counters); + lockfile_release(stats_file); + + if (cache_logfile) { + for (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); + } + } + } + + if (counters->data[STATS_MAXFILES] != 0 && + counters->data[STATS_NUMFILES] > counters->data[STATS_MAXFILES]) { + need_cleanup = true; + } + if (counters->data[STATS_MAXSIZE] != 0 && + counters->data[STATS_TOTALSIZE] > counters->data[STATS_MAXSIZE]) { + need_cleanup = true; + } + + if (need_cleanup) { + char *p = dirname(stats_file); + cleanup_dir(p, + counters->data[STATS_MAXFILES], + counters->data[STATS_MAXSIZE]); + free(p); + } +} + +/* update a normal stat */ +void +stats_update(enum stats stat) +{ + stats_update_size(stat, 0, 0); +} + +/* 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(void) +{ + int dir, i; + struct counters *counters = counters_init(STATS_END); + + /* add up the stats in each directory */ + for (dir = -1; dir <= 0xF; dir++) { + char *fname; + + if (dir == -1) { + fname = format("%s/stats", cache_dir); + } else { + fname = format("%s/%1x/stats", cache_dir, dir); + } + + stats_read(fname, counters); + free(fname); + + /* oh what a nasty hack ... */ + if (dir == -1) { + counters->data[STATS_MAXSIZE] = 0; + } + } + + printf("cache directory %s\n", cache_dir); + + /* and display them */ + for (i = 0; stats_info[i].message; i++) { + enum stats stat = stats_info[i].stat; + + if (counters->data[stat] == 0 && !(stats_info[i].flags & FLAG_ALWAYS)) { + continue; + } + + printf("%s ", 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]); + } + } + + counters_free(counters); +} + +/* zero all the stats structures */ +void +stats_zero(void) +{ + int dir; + unsigned i; + char *fname; + + fname = format("%s/stats", cache_dir); + x_unlink(fname); + free(fname); + + for (dir = 0; dir <= 0xF; dir++) { + struct counters *counters = counters_init(STATS_END); + fname = format("%s/%1x/stats", cache_dir, dir); + if (lockfile_acquire(fname, lock_staleness_limit)) { + stats_read(fname, counters); + for (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_limits(const char *dir, unsigned *maxfiles, unsigned *maxsize) +{ + struct counters *counters = counters_init(STATS_END); + char *sname = format("%s/stats", dir); + stats_read(sname, counters); + *maxfiles = counters->data[STATS_MAXFILES]; + *maxsize = counters->data[STATS_MAXSIZE]; + free(sname); + counters_free(counters); +} + +/* set the per directory limits */ +int +stats_set_limits(long maxfiles, long maxsize) +{ + int dir; + + if (maxfiles != -1) { + maxfiles /= 16; + } + if (maxsize != -1) { + maxsize /= 16; + } + + if (create_dir(cache_dir) != 0) { + return 1; + } + + /* set the limits in each directory */ + for (dir = 0; dir <= 0xF; dir++) { + char *fname, *cdir; + + cdir = format("%s/%1x", cache_dir, dir); + if (create_dir(cdir) != 0) { + free(cdir); + return 1; + } + fname = format("%s/stats", cdir); + free(cdir); + + if (lockfile_acquire(fname, lock_staleness_limit)) { + struct counters *counters = counters_init(STATS_END); + stats_read(fname, counters); + if (maxfiles != -1) { + counters->data[STATS_MAXFILES] = maxfiles; + } + if (maxsize != -1) { + counters->data[STATS_MAXSIZE] = maxsize; + } + stats_write(fname, counters); + lockfile_release(fname); + counters_free(counters); + } + free(fname); + } + + return 0; +} + +/* set the per directory sizes */ +void +stats_set_sizes(const char *dir, size_t num_files, size_t total_size) +{ + struct counters *counters = counters_init(STATS_END); + char *statsfile; + + create_dir(dir); + 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; + 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..a75025f --- /dev/null +++ b/system.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 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 <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <utime.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 + +#ifdef HAVE_STDBOOL_H +# include <stdbool.h> +#else +# ifndef HAVE__BOOL +# ifdef __cplusplus +typedef bool _Bool; +# else +# define _Bool signed char +# endif +# endif +# define bool _Bool +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 +#endif + +#endif /* CCACHE_SYSTEM_H */ @@ -0,0 +1,1835 @@ +#!/bin/sh +# +# A simple test suite for ccache. +# +# Copyright (C) 2002-2007 Andrew Tridgell +# Copyright (C) 2009-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 + +unset CCACHE_BASEDIR +unset CCACHE_CC +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_HASHDIR +unset CCACHE_LOGFILE +unset CCACHE_NLEVELS +unset CCACHE_NODIRECT +unset CCACHE_NOSTATS +unset CCACHE_PATH +unset CCACHE_PREFIX +unset CCACHE_READONLY +unset CCACHE_RECACHE +unset CCACHE_SLOPPINESS +unset CCACHE_TEMPDIR +unset CCACHE_UMASK +unset CCACHE_UNIFY + +test_failed() { + echo "SUITE: \"$testsuite\", TEST: \"$testname\" - $1" + $CCACHE -s + cd .. + echo TEST FAILED + echo "Test data and log file have been left in $TESTDIR" + exit 1 +} + +randcode() { + outfile="$1" + nlines=$2 + i=0 + ( + while [ $i -lt $nlines ]; do + echo "int foo$nlines$i(int x) { return x; }" + i=`expr $i + 1` + done + ) >> "$outfile" +} + + +getstat() { + stat="$1" + value=`$CCACHE -s | grep "$stat" | cut -c34-40` + echo $value +} + +checkstat() { + stat="$1" + expected_value="$2" + value=`getstat "$stat"` + if [ "$expected_value" != "$value" ]; then + test_failed "Expected \"$stat\" to be $expected_value, got $value" + fi +} + +checkfile() { + if [ ! -f $1 ]; then + test_failed "$1 not found" + fi + if [ "`cat $1`" != "$2" ]; then + test_failed "Bad content of $1.\nExpected: $2\nActual: `cat $1`" + fi +} + +checkfilecount() { + expected=$1 + pattern=$2 + dir=$3 + actual=`find $dir -name "$pattern" | wc -l` + if [ $actual -ne $expected ]; then + test_failed "Found $actual (expected $expected) $pattern files in $dir" + fi +} + +sed_in_place() { + expr=$1 + shift + for file in $*; do + sed "$expr" > ${file}.sed < $file + mv ${file}.sed $file + done +} + +backdate() { + touch -t 199901010000 "$@" +} + +run_suite() { + rm -rf $CCACHE_DIR + CCACHE_NODIRECT=1 + export CCACHE_NODIRECT + + echo "starting testsuite $1" + testsuite=$1 + + ${1}_suite + + testname="the tmp directory should be empty" + if [ -d $CCACHE_DIR/tmp ] && [ "`find $CCACHE_DIR/tmp -type f | wc -l`" -gt 0 ]; then + test_failed "$CCACHE_DIR/tmp is not empty" + fi +} + +base_tests() { + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 0 + checkstat 'files in cache' 0 + + j=1 + rm -f *.c + while [ $j -lt 32 ]; do + randcode test$j.c $j + j=`expr $j + 1` + done + + testname="BASIC" + $CCACHE_COMPILE -c test1.c + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkstat 'files in cache' 1 + + testname="BASIC2" + $CCACHE_COMPILE -c test1.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + checkstat 'files in cache' 1 + + testname="debug" + $CCACHE_COMPILE -c test1.c -g + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 2 + checkstat 'files in cache' 2 + + testname="debug2" + $CCACHE_COMPILE -c test1.c -g + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 2 + + testname="output" + $CCACHE_COMPILE -c test1.c -o foo.o + checkstat 'cache hit (preprocessed)' 3 + checkstat 'cache miss' 2 + + testname="link" + $CCACHE_COMPILE test1.c -o test 2> /dev/null + checkstat 'called for link' 1 + + testname="linkobj" + $CCACHE_COMPILE foo.o -o test 2> /dev/null + checkstat 'called for link' 2 + + testname="preprocessing" + $CCACHE_COMPILE -E -c test1.c > /dev/null 2>&1 + checkstat 'called for preprocessing' 1 + + testname="multiple" + $CCACHE_COMPILE -c test1.c test2.c + checkstat 'multiple source files' 1 + + testname="find" + $CCACHE blahblah -c test1.c 2> /dev/null + checkstat "couldn't find the compiler" 1 + + testname="bad" + $CCACHE_COMPILE -c test1.c -I 2> /dev/null + checkstat 'bad compiler arguments' 1 + + testname="unsupported source language" + ln -f test1.c test1.ccc + $CCACHE_COMPILE -c test1.ccc 2> /dev/null + checkstat 'unsupported source language' 1 + + testname="unsupported" + $CCACHE_COMPILE -M foo -c test1.c > /dev/null 2>&1 + checkstat 'unsupported compiler option' 1 + + testname="stdout" + $CCACHE echo foo -c test1.c > /dev/null + checkstat 'compiler produced stdout' 1 + + testname="non-regular" + mkdir testd + $CCACHE_COMPILE -o testd -c test1.c > /dev/null 2>&1 + rmdir testd + checkstat 'output to a non-regular file' 1 + + testname="no-input" + $CCACHE_COMPILE -c -O2 2> /dev/null + checkstat 'no input file' 1 + + testname="CCACHE_DISABLE" + CCACHE_DISABLE=1 $CCACHE_COMPILE -c test1.c 2> /dev/null + checkstat 'cache hit (preprocessed)' 3 + $CCACHE_COMPILE -c test1.c + checkstat 'cache hit (preprocessed)' 4 + + testname="CCACHE_CPP2" + CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O + checkstat 'cache hit (preprocessed)' 4 + checkstat 'cache miss' 3 + + CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c -O -O + checkstat 'cache hit (preprocessed)' 5 + checkstat 'cache miss' 3 + + testname="CCACHE_NOSTATS" + CCACHE_NOSTATS=1 $CCACHE_COMPILE -c test1.c -O -O + checkstat 'cache hit (preprocessed)' 5 + checkstat 'cache miss' 3 + + testname="CCACHE_RECACHE" + CCACHE_RECACHE=1 $CCACHE_COMPILE -c test1.c -O -O + checkstat 'cache hit (preprocessed)' 5 + checkstat 'cache miss' 4 + + # strictly speaking should be 3 - RECACHE causes a double counting! + checkstat 'files in cache' 4 + $CCACHE -c > /dev/null + checkstat 'files in cache' 3 + + testname="CCACHE_HASHDIR" + CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O + checkstat 'cache hit (preprocessed)' 5 + checkstat 'cache miss' 5 + + CCACHE_HASHDIR=1 $CCACHE_COMPILE -c test1.c -O -O + checkstat 'cache hit (preprocessed)' 6 + checkstat 'cache miss' 5 + checkstat 'files in cache' 4 + + testname="comments" + echo '/* a silly comment */' > test1-comment.c + cat test1.c >> test1-comment.c + $CCACHE_COMPILE -c test1-comment.c + rm -f test1-comment* + checkstat 'cache hit (preprocessed)' 6 + checkstat 'cache miss' 6 + + testname="CCACHE_UNIFY" + CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c + checkstat 'cache hit (preprocessed)' 6 + checkstat 'cache miss' 7 + mv test1.c test1-saved.c + echo '/* another comment */' > test1.c + cat test1-saved.c >> test1.c + CCACHE_UNIFY=1 $CCACHE_COMPILE -c test1.c + mv test1-saved.c test1.c + checkstat 'cache hit (preprocessed)' 7 + checkstat 'cache miss' 7 + + testname="cache-size" + for f in *.c; do + $CCACHE_COMPILE -c $f + done + checkstat 'cache hit (preprocessed)' 8 + checkstat 'cache miss' 37 + checkstat 'files in cache' 36 + + $CCACHE -C >/dev/null + + testname="cpp call" + $CCACHE_COMPILE -c test1.c -E > test1.i + checkstat 'cache hit (preprocessed)' 8 + checkstat 'cache miss' 37 + + testname="direct .i compile" + $CCACHE_COMPILE -c test1.c + checkstat 'cache hit (preprocessed)' 8 + checkstat 'cache miss' 38 + + $CCACHE_COMPILE -c test1.i + checkstat 'cache hit (preprocessed)' 9 + checkstat 'cache miss' 38 + + $CCACHE_COMPILE -c test1.i + checkstat 'cache hit (preprocessed)' 10 + checkstat 'cache miss' 38 + + testname="-x c" + $CCACHE_COMPILE -x c -c test1.ccc + checkstat 'cache hit (preprocessed)' 10 + checkstat 'cache miss' 39 + $CCACHE_COMPILE -x c -c test1.ccc + checkstat 'cache hit (preprocessed)' 11 + checkstat 'cache miss' 39 + + testname="-xc" + $CCACHE_COMPILE -xc -c test1.ccc + checkstat 'cache hit (preprocessed)' 12 + checkstat 'cache miss' 39 + + testname="-x none" + $CCACHE_COMPILE -x assembler -x none -c test1.c + checkstat 'cache hit (preprocessed)' 13 + checkstat 'cache miss' 39 + + testname="-x unknown" + $CCACHE_COMPILE -x unknown -c test1.c 2>/dev/null + checkstat 'cache hit (preprocessed)' 13 + checkstat 'cache miss' 39 + checkstat 'unsupported source language' 2 + + testname="-D not hashed" + $CCACHE_COMPILE -DNOT_AFFECTING=1 -c test1.c 2>/dev/null + checkstat 'cache hit (preprocessed)' 14 + checkstat 'cache miss' 39 + + if [ -x /usr/bin/printf ]; then + /usr/bin/printf '#include <wchar.h>\nwchar_t foo[] = L"\xbf";\n' >latin1.c + if CCACHE_DISABLE=1 $COMPILER -c -finput-charset=latin1 latin1.c >/dev/null 2>&1; then + testname="-finput-charset" + CCACHE_CPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c + checkstat 'cache hit (preprocessed)' 14 + checkstat 'cache miss' 40 + $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c + checkstat 'cache hit (preprocessed)' 15 + checkstat 'cache miss' 40 + fi + fi + + testname="compilercheck=mtime" + $CCACHE -Cz >/dev/null + cat >compiler.sh <<EOF +#!/bin/sh +CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink... +export CCACHE_DISABLE +exec $COMPILER "\$@" +# A comment +EOF + chmod +x compiler.sh + backdate compiler.sh + CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + sed_in_place 's/comment/yoghurt/' compiler.sh # Don't change the size + chmod +x compiler.sh + backdate compiler.sh + CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + touch compiler.sh + CCACHE_COMPILERCHECK=mtime $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 2 + + testname="compilercheck=content" + $CCACHE -z >/dev/null + CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + backdate compiler.sh + CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + echo "# Compiler upgrade" >>compiler.sh + backdate compiler.sh + CCACHE_COMPILERCHECK=content $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 2 + + testname="compilercheck=none" + $CCACHE -z >/dev/null + backdate compiler.sh + CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + echo "# Compiler upgrade" >>compiler.sh + CCACHE_COMPILERCHECK=none $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 1 + + testname="compilercheck=command" + $CCACHE -z >/dev/null + backdate compiler.sh + CCACHE_COMPILERCHECK='echo %compiler%' $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + echo "# Compiler upgrade" >>compiler.sh + CCACHE_COMPILERCHECK="echo ./compiler.sh" $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 1 + checkstat '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 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 2 + CCACHE_COMPILERCHECK='echo foo; echo bar' $CCACHE ./compiler.sh -c test1.c + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 2 + + testname="compilercheck=unknown_command" + $CCACHE -z >/dev/null + backdate 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 + checkstat 'compiler check failed' 1 + + testname="no object file" + cat <<'EOF' >test_no_obj.c +int test_no_obj; +EOF + cat <<'EOF' >prefix-remove.sh +#!/bin/sh +"$@" +[ 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 + checkstat 'compiler produced no output' 1 + + testname="empty object file" + cat <<'EOF' >test_empty_obj.c +int test_empty_obj; +EOF + cat <<'EOF' >prefix-empty.sh +#!/bin/sh +"$@" +[ 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 + checkstat 'compiler produced empty output' 1 + + testname="stderr-files" + $CCACHE -Cz >/dev/null + num=`find $CCACHE_DIR -name '*.stderr' | wc -l` + if [ $num -ne 0 ]; then + test_failed "$num stderr files found, expected 0" + fi + cat <<EOF >stderr.c +int stderr(void) +{ + /* Trigger warning by having no return statement. */ +} +EOF + checkstat 'files in cache' 0 + $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 + checkstat 'files in cache' 2 + + testname="zero-stats" + $CCACHE -z > /dev/null + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 0 + checkstat 'files in cache' 2 + + testname="clear" + $CCACHE -C > /dev/null + checkstat 'files in cache' 0 + + rm -f test1.c +} + +base_suite() { + CCACHE_COMPILE="$CCACHE $COMPILER" + base_tests +} + +link_suite() { + if [ `dirname $COMPILER` = . ]; then + ln -s ../ccache $COMPILER + CCACHE_COMPILE="./$COMPILER" + base_tests + else + echo "Compiler ($COMPILER) not taken from PATH -- not running link test" + fi +} + +hardlink_suite() { + CCACHE_COMPILE="$CCACHE $COMPILER" + CCACHE_HARDLINK=1 + export CCACHE_HARDLINK + CCACHE_NOCOMPRESS=1 + export CCACHE_NOCOMPRESS + base_tests + unset CCACHE_HARDLINK + unset CCACHE_NOCOMPRESS +} + +cpp2_suite() { + CCACHE_COMPILE="$CCACHE $COMPILER" + CCACHE_CPP2=1 + export CCACHE_CPP2 + base_tests + unset CCACHE_CPP2 +} + +nlevels4_suite() { + CCACHE_COMPILE="$CCACHE $COMPILER" + CCACHE_NLEVELS=4 + export CCACHE_NLEVELS + base_tests + unset CCACHE_NLEVELS +} + +nlevels1_suite() { + CCACHE_COMPILE="$CCACHE $COMPILER" + CCACHE_NLEVELS=1 + export CCACHE_NLEVELS + base_tests + unset CCACHE_NLEVELS +} + +direct_suite() { + unset CCACHE_NODIRECT + + ################################################################## + # Create some code to compile. + 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 + + ################################################################## + # First compilation is a miss. + testname="first compilation" + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + ################################################################## + # Another compilation should now generate a direct hit. + testname="direct hit" + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 0 + + ################################################################## + # Check that corrupt manifest files are handled and rewritten. + testname="corrupt manifest file" + $CCACHE -z >/dev/null + manifest_file=`find $CCACHE_DIR -name '*.manifest'` + rm $manifest_file + touch $manifest_file + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 0 + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 0 + + ################################################################## + # Compiling with CCACHE_NODIRECT set should generate a preprocessed hit. + testname="preprocessed hit" + $CCACHE -z >/dev/null + CCACHE_NODIRECT=1 $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 0 + + ################################################################## + # Test compilation of a modified include file. + testname="modified include file" + $CCACHE -z >/dev/null + echo "int test3_2;" >>test3.h + backdate test3.h + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + ################################################################## + # A removed but previously compiled header file should be handled + # gracefully. + testname="missing header file" + $CCACHE -z >/dev/null + + mv test1.h test1.h.saved + mv test3.h test3.h.saved + cat <<EOF >test1.h +/* No more include of test3.h */ +int test1; +EOF + backdate test1.h + + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + # Restore + mv test1.h.saved test1.h + mv test3.h.saved test3.h + + rm -f other.d + + ################################################################## + # Check calculation of dependency file names. + $CCACHE -Cz >/dev/null + checkstat 'files in cache' 0 + mkdir test.dir + for ext in .obj "" . .foo.bar; do + testname="dependency file calculation from object file 'test$ext'" + dep_file=test.dir/`echo test$ext | sed 's/\.[^.]*\$//'`.d + $CCACHE $COMPILER -MD -c test.c -o test.dir/test$ext + rm -f $dep_file + $CCACHE $COMPILER -MD -c test.c -o test.dir/test$ext + if [ ! -f $dep_file ]; then + test_failed "$dep_file missing" + fi + done + rm -rf test.dir + checkstat 'files in cache' 12 + + ################################################################## + # Check that -Wp,-MD,file.d works. + testname="-Wp,-MD" + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c -Wp,-MD,other.d test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + rm -f other.d + + $CCACHE $COMPILER -c -Wp,-MD,other.d test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + rm -f other.d + + ################################################################## + # Check that -Wp,-MMD,file.d works. + testname="-Wp,-MMD" + $CCACHE -C >/dev/null + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c -Wp,-MMD,other.d test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + rm -f other.d + + $CCACHE $COMPILER -c -Wp,-MMD,other.d test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + rm -f other.d + + ################################################################## + # Check that -Wp,-MD,file.d,-P disables direct mode. + testname="-Wp,-MD,file.d,-P" + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c -Wp,-MD,$DEVNULL,-P test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + $CCACHE $COMPILER -c -Wp,-MD,$DEVNULL,-P test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + ################################################################## + # Check that -Wp,-MMD,file.d,-P disables direct mode. + testname="-Wp,-MDD,file.d,-P" + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c -Wp,-MMD,$DEVNULL,-P test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + $CCACHE $COMPILER -c -Wp,-MMD,$DEVNULL,-P test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + ################################################################## + # Test some header modifications to get multiple objects in the manifest. + testname="several objects" + $CCACHE -z >/dev/null + for i in 0 1 2 3 4; do + echo "int test1_$i;" >>test1.h + backdate test1.h + $CCACHE $COMPILER -c test.c + $CCACHE $COMPILER -c test.c + done + checkstat 'cache hit (direct)' 5 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 5 + + ################################################################## + # Check that -MD works. + testname="-MD" + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile test.d "test.o: test.c test1.h test3.h test2.h" + + rm -f test.d + + $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile test.d "test.o: test.c test1.h test3.h test2.h" + + ################################################################## + # Check the scenario of running a ccache with direct mode on a cache + # built up by a ccache without direct mode support. + testname="direct mode on old cache" + $CCACHE -z >/dev/null + $CCACHE -C >/dev/null + CCACHE_NODIRECT=1 $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile test.d "test.o: test.c test1.h test3.h test2.h" + + rm -f test.d + + CCACHE_NODIRECT=1 $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + checkfile test.d "test.o: test.c test1.h test3.h test2.h" + + rm -f test.d + + $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 1 + checkfile test.d "test.o: test.c test1.h test3.h test2.h" + + rm -f test.d + + $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 1 + checkfile test.d "test.o: test.c test1.h test3.h test2.h" + + ################################################################## + # Check that -MF works. + testname="-MF" + $CCACHE -C >/dev/null + $CCACHE -z >/dev/null + $CCACHE $COMPILER -c -MD -MF other.d test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + rm -f other.d + + $CCACHE $COMPILER -c -MD -MF other.d test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + ################################################################## + # Check that a missing .d file in the cache is handled correctly. + testname="missing dependency file" + $CCACHE -z >/dev/null + $CCACHE -C >/dev/null + + $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + find $CCACHE_DIR -name '*.d' -exec rm -f '{}' \; + + $CCACHE $COMPILER -c -MD test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + checkfile other.d "test.o: test.c test1.h test3.h test2.h" + + ################################################################## + # Check that stderr from both the preprocessor and the compiler is emitted + # in direct mode too. + testname="cpp stderr" + $CCACHE -z >/dev/null + $CCACHE -C >/dev/null +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 $COMPILER -Wall -W -c cpp-warning.c 2>stderr-orig.txt + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + CCACHE_NODIRECT=1 + export CCACHE_NODIRECT + $CCACHE $COMPILER -Wall -W -c cpp-warning.c 2>stderr-cpp.txt + unset CCACHE_NODIRECT + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + checkfile stderr-cpp.txt "`cat stderr-orig.txt`" + + $CCACHE $COMPILER -Wall -W -c cpp-warning.c 2>stderr-mf.txt + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + checkfile stderr-mf.txt "`cat stderr-orig.txt`" + + ################################################################## + # Check that changes in comments are ignored when hashing. + testname="changes in comments" + $CCACHE -C >/dev/null + $CCACHE -z >/dev/null + cat <<EOF >comments.h +/* + * /* foo comment + */ +EOF + backdate comments.h + cat <<'EOF' >comments.c +#include "comments.h" +char test[] = "\ +/* apple */ // banana"; // foo comment +EOF + + $CCACHE $COMPILER -c comments.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + sed_in_place 's/foo/ignored/' comments.h comments.c + backdate comments.h + + $CCACHE $COMPILER -c comments.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + # Check that comment-like string contents are hashed. + sed_in_place 's/apple/orange/' comments.c + backdate comments.h + + $CCACHE $COMPILER -c comments.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 2 + + ################################################################## + # Check that it's possible to compile and cache an empty source code file. + testname="empty source file" + $CCACHE -Cz >/dev/null + cp /dev/null empty.c + $CCACHE $COMPILER -c empty.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c empty.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + ################################################################## + # Check that empty include files are handled as well. + testname="empty include file" + $CCACHE -Cz >/dev/null + cp /dev/null empty.h + cat <<EOF >include_empty.c +#include "empty.h" +EOF + backdate empty.h + $CCACHE $COMPILER -c include_empty.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c include_empty.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + ################################################################## + # Check that direct mode correctly detects file name/path changes. + testname="__FILE__ in source file" + $CCACHE -Cz >/dev/null + cat <<EOF >file.c +#define file __FILE__ +int test; +EOF + $CCACHE $COMPILER -c file.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c file.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c `pwd`/file.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 2 + + testname="__FILE__ in include file" + $CCACHE -Cz >/dev/null + cat <<EOF >file.h +#define file __FILE__ +int test; +EOF + backdate file.h + cat <<EOF >file_h.c +#include "file.h" +EOF + $CCACHE $COMPILER -c file_h.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c file_h.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + mv file_h.c file2_h.c + $CCACHE $COMPILER -c `pwd`/file2_h.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 2 + + ################################################################## + # Check that direct mode ignores __FILE__ if sloppiness is specified. + testname="__FILE__ in source file, sloppy" + $CCACHE -Cz >/dev/null + cat <<EOF >file.c +#define file __FILE__ +int test; +EOF + CCACHE_SLOPPINESS=file_macro $CCACHE $COMPILER -c file.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=file_macro $CCACHE $COMPILER -c file.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=file_macro $CCACHE $COMPILER -c `pwd`/file.c + checkstat 'cache hit (direct)' 2 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + testname="__FILE__ in include file, sloppy" + $CCACHE -Cz >/dev/null + cat <<EOF >file.h +#define file __FILE__ +int test; +EOF + backdate file.h + cat <<EOF >file_h.c +#include "file.h" +EOF + CCACHE_SLOPPINESS=file_macro $CCACHE $COMPILER -c file_h.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=file_macro $CCACHE $COMPILER -c file_h.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + mv file_h.c file2_h.c + CCACHE_SLOPPINESS=file_macro $CCACHE $COMPILER -c `pwd`/file2_h.c + checkstat 'cache hit (direct)' 2 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + ################################################################## + # Check that we never get direct hits when __TIME__ is used. + testname="__TIME__ in source file" + $CCACHE -Cz >/dev/null + cat <<EOF >time.c +#define time __TIME__ +int test; +EOF + $CCACHE $COMPILER -c time.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c time.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + testname="__TIME__ in include time" + $CCACHE -Cz >/dev/null + cat <<EOF >time.h +#define time __TIME__ +int test; +EOF + backdate time.h + cat <<EOF >time_h.c +#include "time.h" +EOF + $CCACHE $COMPILER -c time_h.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c time_h.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + ################################################################## + # Check that direct mode ignores __TIME__ when sloppiness is specified. + testname="__TIME__ in source file, sloppy" + $CCACHE -Cz >/dev/null + cat <<EOF >time.c +#define time __TIME__ +int test; +EOF + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c time.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c time.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + testname="__TIME__ in include time, sloppy" + $CCACHE -Cz >/dev/null + cat <<EOF >time.h +#define time __TIME__ +int test; +EOF + backdate time.h + cat <<EOF >time_h.c +#include "time.h" +EOF + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c time_h.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c time_h.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + ################################################################## + # Check that a too new include file turns off direct mode. + testname="too new include file" + $CCACHE -Cz >/dev/null + cat <<EOF >new.c +#include "new.h" +EOF + cat <<EOF >new.h +int test; +EOF + touch -t 203801010000 new.h + $CCACHE $COMPILER -c new.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER -c new.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + ################################################################## + # Check that include file mtime is ignored when sloppiness is specified. + testname="too new include file, sloppy" + $CCACHE -Cz >/dev/null + cat <<EOF >new.c +#include "new.h" +EOF + cat <<EOF >new.h +int test; +EOF + touch -t 203801010000 new.h + CCACHE_SLOPPINESS=include_file_mtime $CCACHE $COMPILER -c new.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=include_file_mtime $CCACHE $COMPILER -c new.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 +} + +basedir_suite() { + ################################################################## + # Create some code to compile. + mkdir -p dir1/src dir1/include + cat <<EOF >dir1/src/test.c +#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 + cat <<EOF >stderr.c +#include <stderr.h> +EOF + backdate stderr.h + + ################################################################## + # CCACHE_BASEDIR="" and using absolute include path will result in a cache + # miss. + testname="empty CCACHE_BASEDIR" + $CCACHE -z >/dev/null + + cd dir1 + CCACHE_BASEDIR="" $CCACHE $COMPILER -I`pwd`/include -c src/test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + cd .. + + cd dir2 + CCACHE_BASEDIR="" $CCACHE $COMPILER -I`pwd`/include -c src/test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 2 + cd .. + + ################################################################## + # Setting CCACHE_BASEDIR will result in a cache hit because include paths + # in the preprocessed output are rewritten. + testname="set CCACHE_BASEDIR" + $CCACHE -z >/dev/null + $CCACHE -C >/dev/null + + cd dir1 + CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -c src/test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + cd .. + + cd dir2 + # The space after -I is there to test an extra code path. + CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I `pwd`/include -c src/test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + cd .. + + ################################################################## + # Setting CCACHE_BASEDIR will result in a cache hit because -I arguments + # are rewritten, as are the paths stored in the manifest. + testname="set CCACHE_BASEDIR, direct lookup" + $CCACHE -z >/dev/null + $CCACHE -C >/dev/null + unset CCACHE_NODIRECT + + cd dir1 + CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -c src/test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + cd .. + + cd dir2 + CCACHE_BASEDIR="`pwd`" $CCACHE $COMPILER -I`pwd`/include -c src/test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + cd .. + + ################################################################## + # CCACHE_BASEDIR="" is the default. + testname="default CCACHE_BASEDIR" + cd dir1 + $CCACHE -z >/dev/null + $CCACHE $COMPILER -I`pwd`/include -c src/test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + cd .. + + ################################################################## + # Rewriting triggered by CCACHE_BASEDIR should handle paths with multiple + # slashes correctly. + testname="path normalization" + cd dir1 + $CCACHE -z >/dev/null + CCACHE_BASEDIR=`pwd` $CCACHE $COMPILER -I`pwd`//include -c `pwd`//src/test.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 0 + cd .. + + ################################################################## + # Check that rewriting triggered by CCACHE_BASEDIR also affects stderr. + testname="stderr" + $CCACHE -z >/dev/null + CCACHE_BASEDIR=`pwd` $CCACHE $COMPILER -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat '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 $COMPILER -Wall -W -I`pwd` -c `pwd`/stderr.c -o `pwd`/stderr.o 2>stderr.txt + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat '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 +} + +compression_suite() { + ################################################################## + # Create some code to compile. + cat <<EOF >test.c +int test; +EOF + + ################################################################## + # Check that compressed and uncompressed files get the same hash sum. + testname="compression hash sum" + CCACHE_COMPRESS=1 $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + CCACHE_COMPRESS=1 $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 1 +} + +readonly_suite() { + ################################################################## + # Create some code to compile. + echo "int test;" >test.c + echo "int test2;" >test2.c + + # Cache a compilation. + $CCACHE $COMPILER -c test.c -o test.o + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + # Make the cache readonly + # Check that readonly mode finds the result. + testname="cache hit" + rm -f test.o + chmod -R a-w $CCACHE_DIR + CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp CCACHE_PREFIX=false $CCACHE $COMPILER -c test.c -o test.o + status=$? + chmod -R a+w $CCACHE_DIR + if [ $status -ne 0 ]; then + test_failed "failure when compiling test.c readonly" + fi + if [ ! -f test.o ]; then + test_failed "test.o missing" + fi + + # Check that readonly mode doesn't try to store new results. + testname="cache miss" + files_before=`find $CCACHE_DIR -type f | wc -l` + CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE $COMPILER -c test2.c -o test2.o + if [ $? -ne 0 ]; then + test_failed "failure when compiling test2.c readonly" + fi + if [ ! -f test2.o ]; then + test_failed "test2.o missing" + fi + files_after=`find $CCACHE_DIR -type f | wc -l` + if [ $files_before -ne $files_after ]; then + test_failed "readonly mode stored files in the cache" + fi + + # Check that readonly mode and direct mode works. + unset CCACHE_NODIRECT + files_before=`find $CCACHE_DIR -type f | wc -l` + CCACHE_READONLY=1 CCACHE_TEMPDIR=/tmp $CCACHE $COMPILER -c test.c -o test.o + CCACHE_NODIRECT=1 + export CCACHE_NODIRECT + if [ $? -ne 0 ]; then + test_failed "failure when compiling test2.c readonly" + fi + files_after=`find $CCACHE_DIR -type f | wc -l` + if [ $files_before -ne $files_after ]; then + test_failed "readonly mode + direct mode stored files in the cache" + fi + + ################################################################## +} + +extrafiles_suite() { + ################################################################## + # Create some code to compile. + cat <<EOF >test.c +int test; +EOF + echo a >a + echo b >b + + ################################################################## + # Test the CCACHE_EXTRAFILES feature. + + testname="cache hit" + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + testname="cache miss" + $CCACHE $COMPILER -c test.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + testname="cache miss a b" + CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 2 + + testname="cache hit a b" + CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 2 + + testname="cache miss a b2" + echo b2 >b + CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 3 + + testname="cache hit a b2" + CCACHE_EXTRAFILES="a${PATH_DELIM}b" $CCACHE $COMPILER -c test.c + checkstat 'cache hit (preprocessed)' 3 + checkstat 'cache miss' 3 + + testname="cache miss doesntexist" + CCACHE_EXTRAFILES="doesntexist" $CCACHE $COMPILER -c test.c + checkstat 'cache hit (preprocessed)' 3 + checkstat 'cache miss' 3 + checkstat 'error hashing extra file' 1 +} + +prepare_cleanup_test() { + dir=$1 + rm -rf $dir + mkdir -p $dir + i=0 + while [ $i -lt 10 ]; do + perl -e 'print "A" x 4017' >$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 + i=`expr $i + 1` + 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 +} + +cleanup_suite() { + testname="clear" + prepare_cleanup_test $CCACHE_DIR/a + $CCACHE -C >/dev/null + checkfilecount 0 '*.o' $CCACHE_DIR + checkfilecount 0 '*.d' $CCACHE_DIR + checkfilecount 0 '*.stderr' $CCACHE_DIR + checkstat 'files in cache' 0 + + testname="forced cleanup, no limits" + $CCACHE -C >/dev/null + prepare_cleanup_test $CCACHE_DIR/a + $CCACHE -F 0 -M 0 >/dev/null + $CCACHE -c >/dev/null + checkfilecount 10 '*.o' $CCACHE_DIR + checkfilecount 10 '*.d' $CCACHE_DIR + checkfilecount 10 '*.stderr' $CCACHE_DIR + checkstat 'files in cache' 30 + + testname="forced cleanup, file limit" + $CCACHE -C >/dev/null + prepare_cleanup_test $CCACHE_DIR/a + # (9/10) * 30 * 16 = 432 + $CCACHE -F 432 -M 0 >/dev/null + $CCACHE -c >/dev/null + # floor(0.8 * 9) = 7 + checkfilecount 7 '*.o' $CCACHE_DIR + checkfilecount 7 '*.d' $CCACHE_DIR + checkfilecount 7 '*.stderr' $CCACHE_DIR + checkstat 'files in cache' 21 + 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 + + testname="forced cleanup, size limit" + $CCACHE -C >/dev/null + prepare_cleanup_test $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 + checkfilecount 3 '*.o' $CCACHE_DIR + checkfilecount 3 '*.d' $CCACHE_DIR + checkfilecount 3 '*.stderr' $CCACHE_DIR + checkstat 'files in cache' 9 + 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 + + testname="autocleanup" + $CCACHE -C >/dev/null + for x in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do + prepare_cleanup_test $CCACHE_DIR/$x + done + # (9/10) * 30 * 16 = 432 + $CCACHE -F 432 -M 0 >/dev/null + touch empty.c + checkfilecount 160 '*.o' $CCACHE_DIR + checkfilecount 160 '*.d' $CCACHE_DIR + checkfilecount 160 '*.stderr' $CCACHE_DIR + checkstat 'files in cache' 480 + $CCACHE $COMPILER -c empty.c -o empty.o + # floor(0.8 * 9) = 7 + checkfilecount 157 '*.o' $CCACHE_DIR + checkfilecount 156 '*.d' $CCACHE_DIR + checkfilecount 156 '*.stderr' $CCACHE_DIR + checkstat 'files in cache' 469 + + testname="sibling cleanup" + $CCACHE -C >/dev/null + prepare_cleanup_test $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 + checkfilecount 7 '*.o' $CCACHE_DIR + checkfilecount 7 '*.d' $CCACHE_DIR + checkfilecount 7 '*.stderr' $CCACHE_DIR + checkstat '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 + + testname="new unknown file" + $CCACHE -C >/dev/null + prepare_cleanup_test $CCACHE_DIR/a + touch $CCACHE_DIR/a/abcd.unknown + $CCACHE -c >/dev/null # update counters + checkstat '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 + checkstat 'files in cache' 19 + + testname="old unknown file" + $CCACHE -C >/dev/null + prepare_cleanup_test $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 + + testname="cleanup of tmp files" + $CCACHE -C >/dev/null + touch $CCACHE_DIR/a/abcd.tmp.efgh + $CCACHE -c >/dev/null # update counters + checkstat '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 + checkstat 'files in cache' 0 + + testname="ignore .nfs* files" + prepare_cleanup_test $CCACHE_DIR/a + touch $CCACHE_DIR/a/.nfs0123456789 + $CCACHE -F 0 -M 0 >/dev/null + $CCACHE -c >/dev/null + checkfilecount 1 '.nfs*' $CCACHE_DIR + checkstat 'files in cache' 30 +} + +pch_suite() { + 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 + cat <<EOF >pch2.c +int main() +{ + void *p = NULL; + return 0; +} +EOF + + if $COMPILER -fpch-preprocess pch.h 2>/dev/null && [ -f pch.h.gch ] && $COMPILER pch.c -o pch; then + : + else + echo "Compiler (`$COMPILER --version | head -1`) doesn't support precompiled headers -- not running pch test" + return + fi + + ################################################################## + # Tests for creating a .gch. + + backdate pch.h + + testname="create .gch, -c, no -o" + $CCACHE -zC >/dev/null + $CCACHE $COMPILER -c pch.h + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + rm -f pch.h.gch + $CCACHE $COMPILER -c pch.h + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + if [ ! -f pch.h.gch ]; then + test_failed "pch.h.gch missing" + fi + + testname="create .gch, no -c, -o" + $CCACHE -z >/dev/null + $CCACHE $COMPILER pch.h -o pch.gch + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + $CCACHE $COMPILER pch.h -o pch.gch + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + if [ ! -f pch.gch ]; then + test_failed "pch.gch missing" + fi + + ################################################################## + # Tests for using a .gch. + + rm -f pch.h + backdate pch.h.gch + + testname="no -fpch-preprocess, #include" + $CCACHE -Cz >/dev/null + $CCACHE $COMPILER -c pch.c 2>/dev/null + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 0 + # Preprocessor error because GCC can't find the real include file when + # trying to preprocess: + checkstat 'preprocessor error' 1 + + testname="no -fpch-preprocess, -include, no sloppy time macros" + $CCACHE -Cz >/dev/null + $CCACHE $COMPILER -c -include pch.h pch2.c 2>/dev/null + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 0 + # Must enable sloppy time macros: + checkstat "can't use precompiled header" 1 + + testname="no -fpch-preprocess, -include" + $CCACHE -Cz >/dev/null + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -include pch.h pch2.c 2>/dev/null + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -include pch.h pch2.c 2>/dev/null + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + testname="-fpch-preprocess, #include, no sloppy time macros" + $CCACHE -Cz >/dev/null + $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + # Must enable sloppy time macros: + checkstat "can't use precompiled header" 1 + + testname="-fpch-preprocess, #include, sloppy time macros" + $CCACHE -Cz >/dev/null + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + + testname="-fpch-preprocess, #include, file changed" + echo "updated" >>pch.h.gch # GCC seems to cope with this... + backdate pch.h.gch + CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 1 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 2 + + testname="preprocessor mode" + $CCACHE -Cz >/dev/null + CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 0 + checkstat 'cache miss' 1 + CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 1 + + testname="preprocessor mode, file changed" + echo "updated" >>pch.h.gch # GCC seems to cope with this... + backdate pch.h.gch + CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 1 + checkstat 'cache miss' 2 + CCACHE_NODIRECT=1 CCACHE_SLOPPINESS=time_macros $CCACHE $COMPILER -c -fpch-preprocess pch.c + checkstat 'cache hit (direct)' 0 + checkstat 'cache hit (preprocessed)' 2 + checkstat 'cache miss' 2 +} + +###################################################################### +# main program + +suites="$*" +if [ -n "$CC" ]; then + COMPILER="$CC" +else + COMPILER=gcc +fi +if [ -z "$CCACHE" ]; then + CCACHE=`pwd`/ccache +fi + +compiler_version="`$COMPILER --version 2>&1 | head -1`" +case $compiler_version in + *gcc*|2.95*) + ;; + *) + echo "WARNING: Compiler $COMPILER not supported (version: $compiler_version) -- not running tests" >&2 + exit 0 + ;; +esac + +TESTDIR=testdir.$$ +rm -rf $TESTDIR +mkdir $TESTDIR +cd $TESTDIR || exit 1 + +CCACHE_DIR=`pwd`/.ccache +export CCACHE_DIR +CCACHE_LOGFILE=`pwd`/ccache.log +export CCACHE_LOGFILE + +# --------------------------------------- + +all_suites=" +base +link !win32 +hardlink +cpp2 +nlevels4 +nlevels1 +basedir !win32 +direct +compression +readonly +extrafiles +cleanup +pch +" + +host_os="`uname -s`" +case $host_os in + *MINGW*|*mingw*) + export CCACHE_DETECT_SHEBANG + CCACHE_DETECT_SHEBANG=1 + DEVNULL=NUL + PATH_DELIM=";" + all_suites="`echo "$all_suites" | grep -v '!win32'`" + ;; + *) + DEVNULL=/dev/null + PATH_DELIM=":" + all_suites="`echo "$all_suites" | cut -d' ' -f1`" + ;; +esac + +if [ -z "$suites" ]; then + suites="$all_suites" +fi + +for suite in $suites; do + run_suite $suite +done + +# --------------------------------------- + +cd .. +rm -rf $TESTDIR +echo test done - OK +exit 0 diff --git a/test/framework.c b/test/framework.c new file mode 100644 index 0000000..53a8d60 --- /dev/null +++ b/test/framework.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2010 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 "test/framework.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[32m"; +static const char COLOR_RED[] = "\x1b[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); + + verbose = verbose_output; + + for (suite = suites; *suite; suite++) { + unsigned test_index = 0; + while (1) { + 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) +{ + extern char *cache_logfile; + + ++total_tests; + if (verbose) { + printf("--- TEST: %s ---\n", name); + } + dir_before_test = gnu_getcwd(); + create_dir(name); + cct_chdir(name); + current_test = name; + + cc_reset(); + cache_logfile = getenv("CCACHE_LOGFILE"); +} + +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 && actual) { + fprintf(stderr, " Expression: %s\n", what); + fprintf(stderr, " Expected: %s\n", expected); + fprintf(stderr, " Actual: %s\n", actual); + } else { + fprintf(stderr, " Assertion: %s\n", what); + } + fprintf(stderr, "\n"); +} + +int +cct_check_int_eq(const char *file, int line, const char *expression, + int expected, int actual) +{ + if (expected == actual) { + cct_check_passed(file, line, expression); + return 1; + } else { + char *exp_str = format("%i", expected); + char *act_str = format("%i", actual); + cct_check_failed(file, line, expression, exp_str, act_str); + free(exp_str); + free(act_str); + return 0; + } +} + +int +cct_check_uns_eq(const char *file, int line, const char *expression, + unsigned expected, unsigned actual) +{ + if (expected == actual) { + cct_check_passed(file, line, expression); + return 1; + } else { + char *exp_str = format("%i", expected); + char *act_str = format("%i", actual); + cct_check_failed(file, line, expression, exp_str, act_str); + free(exp_str); + free(act_str); + return 0; + } +} + +int +cct_check_str_eq(const char *file, int line, const char *expression, + const char *expected, const char *actual, int free1, + int free2) +{ + int result; + + if (expected && actual && str_eq(actual, expected)) { + cct_check_passed(file, line, expression); + result = 1; + } 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 = 0; + } + + if (free1) { + free((char *)expected); + } + if (free2) { + free((char *)actual); + } + return result; +} + +int +cct_check_args_eq(const char *file, int line, const char *expression, + struct args *expected, struct args *actual, + int free1, int free2) +{ + int result; + + if (expected && actual && args_equal(actual, expected)) { + cct_check_passed(file, line, expression); + result = 1; + } 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 = 0; + } + + 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(). */ + char *command = format("rm -rf %s", path); + 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..3c616b5 --- /dev/null +++ b/test/framework.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010 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 CHECK(assertion) \ + do { \ + if ((assertion)) { \ + cct_check_passed(__FILE__, __LINE__, #assertion); \ + } else { \ + cct_check_failed(__FILE__, __LINE__, #assertion, NULL, NULL); \ + cct_test_end(); \ + cct_suite_end(); \ + return _test_counter; \ + } \ + } while (0) + +#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 (0) + +/*****************************************************************************/ + +#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 (0) + +#define CHECK_UNS_EQ(expected, actual) \ + do { \ + if (!cct_check_int_eq(__FILE__, __LINE__, #actual, (expected), (actual))) { \ + cct_test_end(); \ + cct_suite_end(); \ + return _test_counter; \ + } \ + } while (0) + +/*****************************************************************************/ + +#define CHECK_STR_EQ(expected, actual) \ + CHECK_POINTER_EQ_BASE(str, expected, actual, 0, 0) + +#define CHECK_STR_EQ_FREE1(expected, actual) \ + CHECK_POINTER_EQ_BASE(str, expected, actual, 1, 0) + +#define CHECK_STR_EQ_FREE2(expected, actual) \ + CHECK_POINTER_EQ_BASE(str, expected, actual, 0, 1) + +#define CHECK_STR_EQ_FREE12(expected, actual) \ + CHECK_POINTER_EQ_BASE(str, expected, actual, 1, 1) + +/*****************************************************************************/ + +#define CHECK_ARGS_EQ(expected, actual) \ + CHECK_POINTER_EQ_BASE(args, expected, actual, 0, 0) + +#define CHECK_ARGS_EQ_FREE1(expected, actual) \ + CHECK_POINTER_EQ_BASE(args, expected, actual, 1, 0) + +#define CHECK_ARGS_EQ_FREE2(expected, actual) \ + CHECK_POINTER_EQ_BASE(args, expected, actual, 0, 1) + +#define CHECK_ARGS_EQ_FREE12(expected, actual) \ + CHECK_POINTER_EQ_BASE(args, expected, actual, 1, 1) + +/*****************************************************************************/ + +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 cct_test_begin(const char *name); +void cct_test_end(); +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); +int cct_check_int_eq(const char *file, int line, const char *expression, + int expected, int actual); +int cct_check_uns_eq(const char *file, int line, const char *expression, + unsigned expected, unsigned actual); +int cct_check_str_eq(const char *file, int line, const char *expression, + const char *expected, const char *actual, int free1, + int free2); +int cct_check_args_eq(const char *file, int line, const char *expression, + struct args *expected, struct args *actual, + int free1, int 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..739d452 --- /dev/null +++ b/test/main.c @@ -0,0 +1,90 @@ +/* Mode: -*-c-*- */ +/* + * Copyright (C) 2010 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 "test/framework.h" +#ifdef HAVE_GETOPT_LONG +#include <getopt.h> +#else +#include "getopt_long.h" +#endif + +#define SUITE(name) unsigned suite_##name(unsigned); +#include "test/suites.h" +#undef SUITE + +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 "test/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; + + 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..0d07dda --- /dev/null +++ b/test/suites.h @@ -0,0 +1,9 @@ +SUITE(args) +SUITE(argument_processing) +SUITE(compopt) +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..50608fc --- /dev/null +++ b/test/test_args.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010 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 "test/framework.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_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_SUITE_END diff --git a/test/test_argument_processing.c b/test/test_argument_processing.c new file mode 100644 index 0000000..e6de579 --- /dev/null +++ b/test/test_argument_processing.c @@ -0,0 +1,237 @@ +/* + * 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 the processing of compiler arguments. + */ + +#include "ccache.h" +#include "test/framework.h" +#include "test/util.h" + +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_UNS_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_UNS_EQ(1, stats_get_pending(STATS_UNSUPPORTED)); + + args_free(orig); +} + +TEST(dependency_flags_should_only_be_sent_to_the_preprocessor) +{ +#define CMD \ + "cc -c -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 " 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(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 -c -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 *base_dir; + extern char *current_working_dir; + struct args *orig = + args_init_from_string("cc --sysroot=/some/directory -c foo.c"); + struct args *act_cpp = NULL, *act_cc = NULL; + create_file("foo.c", ""); + + CHECK(cc_process_args(orig, &act_cpp, &act_cc)); + CHECK_STR_EQ(act_cpp->argv[1], "--sysroot=/some/directory"); + + cc_reset(); + base_dir = "/some"; + current_working_dir = get_cwd(); + + CHECK(cc_process_args(orig, &act_cpp, &act_cc)); + CHECK(str_startswith(act_cpp->argv[1], "--sysroot=../")); + + args_free(orig); + base_dir = NULL; + current_working_dir = NULL; +} + +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 -c -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 -c -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 -c -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 -c -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 -c -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_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 -c -MD -MP -MFfoo.d -MQfoo.d -MQ foo.o"); + 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_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 -c -MD -MP -MFfoo.d -MTfoo.d -MQ foo.o"); + 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_SUITE_END diff --git a/test/test_compopt.c b/test/test_compopt.c new file mode 100644 index 0000000..509825c --- /dev/null +++ b/test/test_compopt.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010 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 "test/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_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_SUITE_END diff --git a/test/test_counters.c b/test/test_counters.c new file mode 100644 index 0000000..a00d1ee --- /dev/null +++ b/test/test_counters.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 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 "test/framework.h" +#include "test/util.h" + +TEST_SUITE(counters) + +TEST(counters_init_0_should_allocate_0) +{ + struct counters *counters = counters_init(0); + + CHECK_UNS_EQ(0, counters->allocated); + CHECK_UNS_EQ(0, counters->size); + + counters_free(counters); +} + +TEST(counters_init_7_should_allocate_32) +{ + int i; + struct counters *counters = counters_init(7); + + CHECK_UNS_EQ(32, counters->allocated); + CHECK_UNS_EQ(7, counters->size); + for (i = 0; i < 7; i++) { + CHECK_UNS_EQ(0, counters->data[i]); + } + + counters_free(counters); +} + +TEST(counters_resize_50_should_allocate_96) +{ + struct counters *counters = counters_init(0); + + CHECK_UNS_EQ(0, counters->allocated); + counters_resize(counters, 50); + CHECK_UNS_EQ(50, counters->size); + CHECK_UNS_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..b9d58fb --- /dev/null +++ b/test/test_hash.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 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 "test/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..225841a --- /dev/null +++ b/test/test_hashutil.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2010 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 "test/framework.h" +#include "test/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); + 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")); + CHECK(hash_equal(&h1, &h2)); +} + +TEST(hash_multicommand_output) +{ + struct mdfour h1, h2; + hash_start(&h1); + hash_start(&h2); + 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")); + 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_SUITE_END diff --git a/test/test_lockfile.c b/test/test_lockfile.c new file mode 100644 index 0000000..ec98894 --- /dev/null +++ b/test/test_lockfile.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 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 "test/framework.h" +#include "test/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"); +#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..acf6a34 --- /dev/null +++ b/test/test_stats.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 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 "test/framework.h" +#include "test/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_UNS_EQ(100, counters->size); + CHECK_UNS_EQ(73, counters->data[73]); + + stats_write("stats", counters); + CHECK_UNS_EQ(100, counters->size); + CHECK_UNS_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..b8d24be --- /dev/null +++ b/test/test_util.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 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 "test/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("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_SUITE_END diff --git a/test/util.c b/test/util.c new file mode 100644 index 0000000..9196d62 --- /dev/null +++ b/test/util.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 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 "test/util.h" + +bool +path_exists(const char *path) +{ + struct stat st; + return lstat(path, &st) == 0; +} + +bool +is_symlink(const char *path) +{ + struct stat st; + return lstat(path, &st) == 0 && S_ISLNK(st.st_mode); +} + +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..dd942d4 --- /dev/null +++ b/test/util.h @@ -0,0 +1,8 @@ +#ifndef TEST_UTIL_H +#define TEST_UTIL_H + +bool path_exists(const char *path); +bool is_symlink(const char *path); +void create_file(const char *path, const char *content); + +#endif @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2002 Andrew Tridgell + * + * 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) +{ + unsigned char c; + int i; + static bool done; + + if (done) return; + done = true; + + memset(tokens, 0, sizeof(tokens)); + for (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 (i = 0; s_tokens[i]; i++) { + 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) +{ + size_t ofs; + unsigned char q; + int i; + + build_table(); + + for (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) { + 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) { + q = p[ofs]; + 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; +} @@ -0,0 +1,1210 @@ +/* + * Copyright (C) 2002 Andrew Tridgell + * Copyright (C) 2009-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 <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> +#endif + +static FILE *logfile; + +static bool +init_log(void) +{ + extern char *cache_logfile; + + if (logfile) { + return true; + } + if (!cache_logfile) { + return false; + } + logfile = fopen(cache_logfile, "a"); + if (logfile) { + return true; + } else { + return false; + } +} + +static void +log_prefix(void) +{ +#ifdef HAVE_GETTIMEOFDAY + char timestamp[100]; + struct timeval tv; + struct tm *tm; + + gettimeofday(&tv, NULL); +#ifdef __MINGW64_VERSION_MAJOR + tm = _localtime32(&tv.tv_sec); +#else + tm = localtime(&tv.tv_sec); +#endif + strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", tm); + fprintf(logfile, "[%s.%06d %-5d] ", timestamp, (int)tv.tv_usec, + (int)getpid()); +#else + fprintf(logfile, "[%-5d] ", (int)getpid()); +#endif +} + +/* + * Write a message to the CCACHE_LOGFILE location (adding a newline). + */ +void +cc_log(const char *format, ...) +{ + va_list ap; + + if (!init_log()) { + return; + } + + log_prefix(); + va_start(ap, format); + vfprintf(logfile, format, ap); + va_end(ap); + fprintf(logfile, "\n"); + fflush(logfile); +} + +/* + * Log an executed command to the CCACHE_LOGFILE location. + */ +void +cc_log_argv(const char *prefix, char **argv) +{ + if (!init_log()) { + return; + } + + log_prefix(); + fputs(prefix, logfile); + print_command(logfile, argv); + fflush(logfile); +} + +/* something went badly wrong! */ +void +fatal(const char *format, ...) +{ + va_list ap; + char msg[1000]; + + va_start(ap, format); + vsnprintf(msg, sizeof(msg), format, ap); + va_end(ap); + + cc_log("FATAL: %s", msg); + fprintf(stderr, "ccache: FATAL: %s\n", msg); + + 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) +{ + char buf[10240]; + int n; + gzFile gz_in; + + gz_in = gzdopen(dup(fd_in), "rb"); + + if (!gz_in) { + fatal("Failed to copy fd"); + } + + while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) { + ssize_t count, written = 0; + do { + count = write(fd_out, buf + written, n - written); + if (count == -1 && errno != EINTR) { + fatal("Failed to copy fd"); + } + 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 + +/* + * Copy src to dest, decompressing src if needed. compress_dest decides whether + * dest will be compressed. + */ +int +copy_file(const char *src, const char *dest, int compress_dest) +{ + int fd_in = -1, fd_out = -1; + gzFile gz_in = NULL, gz_out = NULL; + char buf[10240]; + int n, written; + char *tmp_name; +#ifndef _WIN32 + mode_t mask; +#endif + struct stat st; + int errnum; + + tmp_name = format("%s.%s.XXXXXX", dest, tmp_string()); + cc_log("Copying %s to %s via %s (%s)", + src, dest, tmp_name, compress_dest ? "compressed": "uncompressed"); + + /* open source file */ + fd_in = open(src, O_RDONLY | O_BINARY); + if (fd_in == -1) { + cc_log("open error: %s", strerror(errno)); + return -1; + } + + gz_in = gzdopen(fd_in, "rb"); + if (!gz_in) { + cc_log("gzdopen(src) error: %s", strerror(errno)); + close(fd_in); + return -1; + } + + /* open destination file */ + fd_out = mkstemp(tmp_name); + if (fd_out == -1) { + cc_log("mkstemp error: %s", strerror(errno)); + goto error; + } + + if (compress_dest) { + /* + * 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. + */ + if (fstat(fd_in, &st) != 0) { + cc_log("fstat error: %s", strerror(errno)); + goto error; + } + if (file_size(&st) == 0) { + compress_dest = 0; + } + } + + if (compress_dest) { + gz_out = gzdopen(dup(fd_out), "wb"); + if (!gz_out) { + cc_log("gzdopen(dest) error: %s", strerror(errno)); + goto error; + } + } + + while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) { + if (compress_dest) { + written = gzwrite(gz_out, buf, n); + } else { + ssize_t count; + written = 0; + do { + count = write(fd_out, buf + written, n - written); + if (count == -1 && errno != EINTR) { + break; + } + written += count; + } while (written < n); + } + if (written != n) { + if (compress_dest) { + cc_log("gzwrite error: %s (errno: %s)", + gzerror(gz_in, &errnum), + strerror(errno)); + } else { + cc_log("write error: %s", strerror(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. + */ + gzerror(gz_in, &errnum); + if (!gzeof(gz_in) || (errnum != Z_OK && errnum != Z_STREAM_END)) { + cc_log("gzread error: %s (errno: %s)", + gzerror(gz_in, &errnum), strerror(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 + /* get perms right on the tmp file */ + mask = umask(0); + fchmod(fd_out, 0666 & ~mask); + umask(mask); +#endif + + /* the close can fail on NFS if out of space */ + if (close(fd_out) == -1) { + cc_log("close error: %s", strerror(errno)); + goto error; + } + + if (x_rename(tmp_name, dest) == -1) { + cc_log("rename error: %s", strerror(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); + return -1; +} + +/* Run copy_file() and, if successful, delete the source file. */ +int +move_file(const char *src, const char *dest, int compress_dest) +{ + int ret; + + ret = copy_file(src, dest, compress_dest); + 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_dest) +{ + if (compress_dest) { + return move_file(src, dest, compress_dest); + } else { + return x_rename(src, dest); + } +} + +/* test if a file is zlib compressed */ +bool +file_is_compressed(const char *filename) +{ + FILE *f; + + 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; +} + +/* + * Return a static string with the current hostname. + */ +const char * +get_hostname(void) +{ + static char hostname[200] = ""; + + if (!hostname[0]) { + strcpy(hostname, "unknown"); +#if HAVE_GETHOSTNAME + gethostname(hostname, sizeof(hostname)-1); +#endif + hostname[sizeof(hostname)-1] = 0; + } + + return hostname; +} + +/* + * Return a string to be used to distinguish temporary files. 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", get_hostname(), (unsigned)getpid()); + } + + return ret; +} + +/* Return the hash result as a hex string. Caller frees. */ +char * +format_hash_as_string(const unsigned char *hash, unsigned size) +{ + char *ret; + int i; + + ret = x_malloc(53); + for (i = 0; i < 16; i++) { + sprintf(&ret[i*2], "%02x", (unsigned) hash[i]); + } + sprintf(&ret[i*2], "-%u", 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" + "# http://www.brynosaurus.com/cachedir/\n"; + +int +create_cachedirtag(const char *dir) +{ + struct stat st; + FILE *f; + char *filename = format("%s/CACHEDIR.TAG", dir); + if (stat(filename, &st) == 0) { + if (S_ISREG(st.st_mode)) { + goto success; + } + errno = EEXIST; + goto error; + } + 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; + char *ptr = NULL; + + va_start(ap, format); + 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; + 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) +{ + char *ret; +#ifndef HAVE_STRNDUP + size_t m; + + if (!s) + return NULL; + m = 0; + while (m < n && s[m]) { + m++; + } + ret = malloc(m + 1); + if (ret) { + memcpy(ret, s, m); + ret[m] = '\0'; + } +#else + 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) +{ + void *ret; + 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; + } + 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) +{ + void *ret; + 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; + } + 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) +{ + void *p2; + if (!ptr) return x_malloc(size); + p2 = realloc(ptr, size); + if (!p2) { + fatal("x_realloc: Could not allocate %lu bytes", (unsigned long)size); + } + return p2; +} + + +/* + * This is like x_asprintf() but frees *ptr if *ptr != NULL. + */ +void +x_asprintf2(char **ptr, const char *format, ...) +{ + char *saved = *ptr; + va_list ap; + + *ptr = NULL; + va_start(ap, format); + if (vasprintf(ptr, format, ap) == -1) { + fatal("Out of memory in x_asprintf2"); + } + va_end(ap); + + if (!ptr) fatal("Out of memory in x_asprintf2"); + 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; + struct dirent *de; + + d = opendir(dir); + if (!d) return; + + while ((de = readdir(d))) { + char *fname; + struct stat st; + + if (str_eq(de->d_name, ".")) continue; + if (str_eq(de->d_name, "..")) continue; + + if (strlen(de->d_name) == 0) continue; + + fname = format("%s/%s", dir, de->d_name); + if (lstat(fname, &st)) { + if (errno != ENOENT) { + perror(fname); + } + 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 *s) +{ + char *p; + p = strrchr(s, '/'); + if (p) s = p + 1; +#ifdef _WIN32 + p = strrchr(s, '\\'); + if (p) s = p + 1; +#endif + + return x_strdup(s); +} + +/* return the dir name of a file - caller frees */ +char * +dirname(char *s) +{ + char *p; + char *p2 = NULL; + s = x_strdup(s); + p = strrchr(s, '/'); +#ifdef _WIN32 + p2 = strrchr(s, '\\'); +#endif + if (p < p2) + p = p2; + if (p) { + *p = 0; + return s; + } else { + free(s); + return x_strdup("."); + } +} + +/* + * 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); + const char *p; + + for (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 +} + +/* a safe open/create for read-write */ +int +safe_open(const char *fname) +{ + int fd = open(fname, O_RDWR|O_BINARY); + if (fd == -1 && errno == ENOENT) { + fd = open(fname, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0666); + if (fd == -1 && errno == EEXIST) { + fd = open(fname, O_RDWR|O_BINARY); + } + } + return fd; +} + +/* Format a size (in KiB) as a human-readable string. Caller frees. */ +char * +format_size(size_t v) +{ + char *s; + if (v >= 1024*1024) { + s = format("%.1f Gbytes", v/((double)(1024*1024))); + } else if (v >= 1024) { + s = format("%.1f Mbytes", v/((double)(1024))); + } else { + s = format("%.0f Kbytes", (double)v); + } + return s; +} + +/* return a value in multiples of 1024 give a string that can end + in K, M or G +*/ +size_t +value_units(const char *s) +{ + char m; + double v = atof(s); + m = s[strlen(s)-1]; + switch (m) { + case 'G': + case 'g': + default: + v *= 1024*1024; + break; + case 'M': + case 'm': + v *= 1024; + break; + case 'K': + case 'k': + v *= 1; + break; + } + return (size_t)v; +} + +#ifndef _WIN32 +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); + if (maxlen >= 4096) { + return maxlen; + } else { + return 4096; + } +#endif +} + +/* + a sane realpath() function, trying to cope with stupid path limits and + a broken API +*/ +char * +x_realpath(const char *path) +{ + long maxlen = path_max(path); + char *ret, *p; + + ret = x_malloc(maxlen); + +#if HAVE_REALPATH + p = realpath(path, 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; +} +#endif /* !_WIN32 */ + +/* a getcwd that will returns an allocated buffer */ +char * +gnu_getcwd(void) +{ + unsigned size = 128; + + while (1) { + 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; + } +} + +/* create an empty file */ +int +create_empty_file(const char *fname) +{ + int fd; + + fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666); + if (fd == -1) { + return -1; + } + close(fd); + return 0; +} + +/* + * 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 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) +{ + char *pwd; + char *cwd; + struct stat st_pwd; + struct stat st_cwd; + + cwd = gnu_getcwd(); + if (!cwd) { + return NULL; + } + 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 + * strings. + */ +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 > s1 && ((*p1 && *p1 != '/' ) || (*p2 && *p2 != '/'))) { + p1--; + p2--; + } + return p1 - s1; +} + +/* + * Compute a relative path from from to to. Caller frees. + */ +char * +get_relative_path(const char *from, const char *to) +{ + size_t common_prefix_len; + int i; + const char *p; + char *result; + + if (!*to || *to != '/') { + return x_strdup(to); + } + + result = x_strdup(""); + common_prefix_len = common_dir_prefix_length(from, to); + for (p = from + common_prefix_len; *p; p++) { + if (*p == '/') { + x_asprintf2(&result, "../%s", result); + } + } + if (strlen(to) > common_prefix_len) { + p = to + common_prefix_len + 1; + while (*p == '/') { + p++; + } + x_asprintf2(&result, "%s%s", result, p); + } + i = strlen(result) - 1; + while (i >= 0 && result[i] == '/') { + result[i] = '\0'; + i--; + } + 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 1; +#ifdef _WIN32 + if (strchr(path, '\\')) + return 1; +#endif + return 0; +} + +/* + * 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 +} + +/* + * Rename oldpath to newpath (deleting newpath). + */ +int +x_rename(const char *oldpath, const char *newpath) +{ +#ifdef _WIN32 + /* Windows' rename() refuses to overwrite an existing file. */ + unlink(newpath); /* not x_unlink, as x_unlink calls x_rename */ +#endif + return rename(oldpath, newpath); +} + +/* + * 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 (as-tmp)", path); + return unlink(path); +} + +/* + * Remove path, NFS safe. + */ +int +x_unlink(const char *path) +{ + /* + * 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. + */ + const char* tmp_name = format("%s.%s.rmXXXXXX", path, tmp_string()); + cc_log("Unlink %s via %s", path, tmp_name); + if (x_rename(path, tmp_name) == -1) { + return -1; + } + if (unlink(tmp_name) == -1) { + return -1; + } + return 0; +} + +#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); + ssize_t len; + char *buf; +#ifdef PATH_MAX + maxlen = PATH_MAX; +#elif defined(MAXPATHLEN) + maxlen = MAXPATHLEN; +#elif defined(_PC_PATH_MAX) + maxlen = pathconf(path, _PC_PATH_MAX); +#endif + if (maxlen < 4096) maxlen = 4096; + + buf = x_malloc(maxlen); + 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) +{ + int fd, ret; + size_t pos = 0, allocated; + + if (size_hint == 0) { + struct stat st; + if (stat(path, &st) == 0) { + size_hint = st.st_size; + } + } + size_hint = (size_hint < 1024) ? 1024 : size_hint; + + fd = open(path, O_RDONLY); + if (fd == -1) { + return false; + } + allocated = size_hint; + *data = x_malloc(allocated); + ret = 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. + */ +char * +read_text_file(const char *path) +{ + size_t size; + char *data; + + if (read_file(path, 0, &data, &size)) { + data = x_realloc(data, size + 1); + data[size] = '\0'; + return data; + } else { + return NULL; + } +} diff --git a/version.c b/version.c new file mode 100644 index 0000000..5081b0b --- /dev/null +++ b/version.c @@ -0,0 +1 @@ +const char CCACHE_VERSION[] = "3.1.6"; diff --git a/zlib/adler32.c b/zlib/adler32.c new file mode 100644 index 0000000..007ba26 --- /dev/null +++ b/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* 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 */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(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; + MOD4(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); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + 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); +} diff --git a/zlib/compress.c b/zlib/compress.c new file mode 100644 index 0000000..df04f01 --- /dev/null +++ b/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + 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 0.1% larger than sourceLen plus + 12 bytes. 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. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/zlib/crc32.c b/zlib/crc32.c new file mode 100644 index 0000000..f658a9e --- /dev/null +++ b/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 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(). + */ + +#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 + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include <limits.h> +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + 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)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long 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() +{ + unsigned long c; + int n, k; + unsigned long 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 = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)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] = REV(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] = REV(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 unsigned long 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 unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", 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 unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long 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; + unsigned 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)) { + u4 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 u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 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 u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 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)(REV(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]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_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 */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* 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; +} diff --git a/zlib/crc32.h b/zlib/crc32.h new file mode 100644 index 0000000..8053b61 --- /dev/null +++ b/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long 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..29ce1f6 --- /dev/null +++ b/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * 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://www.ietf.org/rfc/rfc1951.txt + * + * 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.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + 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 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)); +#ifndef FASTEST +#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 +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#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 */ + +#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. + */ + +/* 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 + +/* =========================================================================== + * 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) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#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->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 = (char*)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 length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (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); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +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 deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + 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 (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + 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, as well as wrap. + * 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 destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * 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 = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->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_FINISH || 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 == 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 != 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 != 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 != 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 != 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 && flush <= 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 = (*(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 { /* 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 */ + } + } + 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(dest, 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(ds, 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(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, 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; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + 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->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 */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(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; +} + +#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; + + 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.) + */ + /* %%% avoid this when Z_RLE */ + 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) return; + + /* 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 >= MIN_MATCH) { + 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 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); +} + +/* =========================================================================== + * 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, eof) { \ + _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), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? 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); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : 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 = NIL; /* 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: + */ + 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). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() 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); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : 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 = NIL; /* 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: + */ + 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). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() 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; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * 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 run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end 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 encodable run. + */ + 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 */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } 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); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/zlib/deflate.h b/zlib/deflate.h new file mode 100644 index 0000000..05a5ab3 --- /dev/null +++ b/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 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 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; /* STORED (for zip only) or 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 supress 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 */ + int last_eob_len; /* bit length of EOB code for last block */ + +#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. + */ + +} 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. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#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 _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _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/gzio.c b/zlib/gzio.c new file mode 100644 index 0000000..7e90f49 --- /dev/null +++ b/zlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include <stdio.h> + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "<fd:%d>", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + 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. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include <stdarg.h> + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +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; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, 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 < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, 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(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + 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. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + 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. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + 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. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/zlib/inffast.c b/zlib/inffast.c new file mode 100644 index 0000000..bbee92e --- /dev/null +++ b/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 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 inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + 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 write; /* 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 this; /* 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; + write = state->write; + 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; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.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; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.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) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 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 (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - 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 */ + this = dcode[this.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 */ + this = lcode[this.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 write == 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..1e88d2d --- /dev/null +++ b/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 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 inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/zlib/inffixed.h b/zlib/inffixed.h new file mode 100644 index 0000000..75ed4b5 --- /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 the compression 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..792fdee --- /dev/null +++ b/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 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 write == 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, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +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; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +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 > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + 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) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + 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; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + 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}", 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, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, 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->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 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) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + 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; + 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 this; /* 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 (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 = REVERSE(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) 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 */ + 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; + 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 = (code const 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 (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.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 (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.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; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const 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 = (code const 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; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + 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->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - 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 + REVERSE(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 || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, 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); + 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 inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* 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 id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + 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; +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(dest, source, sizeof(z_stream)); + zmemcpy(copy, 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; +} diff --git a/zlib/inflate.h b/zlib/inflate.h new file mode 100644 index 0000000..07bd3e7 --- /dev/null +++ b/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 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: 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: waiting for length/lit 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 the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K 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 write; /* 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 */ +}; diff --git a/zlib/inftrees.c b/zlib/inftrees.c new file mode 100644 index 0000000..8a9c13f --- /dev/null +++ b/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 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.3 Copyright 1995-2005 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 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 this; /* 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, 201, 196}; + 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 */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; 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 when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + 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 - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.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] = this; + } 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 - MAXD) + 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 rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* 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; + } + + /* 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..b1104c8 --- /dev/null +++ b/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 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 dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int 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..395e4e1 --- /dev/null +++ b/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * 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. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * 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, ct_data *ltree, + ct_data *dtree)); +local void set_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 |= (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 |= 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 |= (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 |= (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: */ + 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; + + /* 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 _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 _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 _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; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#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 _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 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 */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _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); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true 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 (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_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, eof); + +#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)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (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 (eof) { + 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*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _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; + ct_data *ltree; /* literal tree */ + 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); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : 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 */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + 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..72facf9 --- /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 _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 _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..03a9431 --- /dev/null +++ b/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 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. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#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 + +/* 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 + +/* 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 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# ifdef VMS +# include <unixio.h> /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# 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(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# 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..0228179 --- /dev/null +++ b/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 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://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + 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 (for example if an input file is mmap'ed), 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 { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb 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 nb of bytes output so far */ + + 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 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* 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, + 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 accumualte 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. + + 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). If deflate does not return + Z_STREAM_END, then 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 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. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +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, or Z_BLOCK. 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. + + 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 the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + 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 only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 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() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. 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. + + 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 + if next_in or next_out was 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 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 a parameter is invalid (such as an invalid + method). 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. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. 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 in + deflate or deflate2. 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 (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). 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 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 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(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +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, 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 -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_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +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 + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. 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 (such as NULL dictionary) 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 inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a 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 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 NULL). +*/ + +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. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the 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 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 paramaters 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 *, 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 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. This + function 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 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) + */ + + + /* 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 easily 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. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + 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 compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + 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. +*/ + + +typedef voidp gzFile; + +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", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + 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. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +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 (in 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 gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +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 was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -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 actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + 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. +*/ + +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. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +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. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. 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 returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +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. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +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. +*/ + +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. +*/ + + /* 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 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. +*/ + +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 NULL, this function returns the required initial + value for the 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, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/zlib/zutil.c b/zlib/zutil.c new file mode 100644 index 0000000..d55f594 --- /dev/null +++ b/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +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 (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (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 +#ifdef STDC +# 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 z_verbose = verbose; + +void 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 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 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 zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#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 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 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 zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void 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 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 zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/zlib/zutil.h b/zlib/zutil.h new file mode 100644 index 0000000..b7d5eff --- /dev/null +++ b/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 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 + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include <stddef.h> +# endif +# include <string.h> +# include <stdlib.h> +#endif +#ifdef NO_ERRNO_H +# ifdef _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. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include <errno.h> +# endif +#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 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 = (char*)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 +# 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 + +#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 +# ifdef M_I86 + #include <malloc.h> +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# 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 + +#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)) +# 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 + + /* 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(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# 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) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# 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 + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include <stdio.h> + extern int z_verbose; + extern void 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 + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#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);} + +#endif /* ZUTIL_H */ |