diff options
author | pixel <pixel> | 2004-11-27 21:35:19 +0000 |
---|---|---|
committer | pixel <pixel> | 2004-11-27 21:35:19 +0000 |
commit | 3f7070bf177b743be0eeb8c404a620f72eb15ab6 (patch) | |
tree | a22fa7d0a1fd362bfc858f8e7e2062fdd5b252ce /lib | |
parent | 6ba597d46a93aaa9a17eb8a9fe8f3bcdedf686c0 (diff) |
Large dos2unix commit...
Diffstat (limited to 'lib')
78 files changed, 24052 insertions, 24056 deletions
diff --git a/lib/Action.cc b/lib/Action.cc index e5825b9..8e8e98d 100644 --- a/lib/Action.cc +++ b/lib/Action.cc @@ -1,91 +1,91 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "BString.h" -#include "Action.h" -#include "HttpServ.h" - -Action * Action::start = 0; - -static int counter = 0; - -static String genurl(const String & u) { - if (u.strlen()) { - return u; - } else { - // Si l'url passée en paramètre est vide, on génère une URL - // sous la forme TmpXXXX où XXXX est une valeur qui s'incrémente. - return String("Tmp") + (counter++); - } -} - -Action::Action(const String & u) : next(start), prev(0), URL(genurl(u)), hastoclean(false), accessed(false) { - start = this; - if (next) next->prev = this; -} - -Action::~Action() { - if (start == this) { - start = next; - } - if (next) next->prev = prev; - if (prev) prev->next = next; -} - -Action * Action::Look4URL(const String & URL) { - Action * p; - -// cerr << "Looking for " << URL << endl; - for (p = start; p; p = p->next) { -// cerr << "p->GetURL() = " << p->GetURL() << endl; - if (!p->GetURL().strlen()) { - // Si l'action que l'on vient de tester n'a pas d'URL, elle ne sert à rien. - // On l'efface donc de notre liste. GetURL renvoie une chaine vide si l'action - // était déclarée en mode CleanUp, puis a été accédée. - delete p; - } else { - if (URL == p->GetURL()) return p; - } - } - - return 0; -} - -/* - * Voici la skin principale. Elle nécessite un fichier 'grain.png' dans le répertoire datas - * et un fichier 'style.css' (fournis) - */ - -void Action::SendHead(Handle * h) { - (*h) << "<HTML><HEAD><TITLE>" << GetTitle() << "</TITLE>" << endnl << - "<META http-equiv=\"Content-Style-Type\" content=\"text/css\">" << endnl << - "<LINK REL=STYLESHEET HREF=\"/image/style.css\" TYPE=\"text/css\">" << endnl << - "</HEAD><BODY BGCOLOR=\"#aaaaaa\" BACKGROUND=\"/image/grain.png\">" << endnl << - "<center><TABLE WIDTH=\"50%\" BORDER=3 cellspacing=1 BGCOLOR=\"#ffffff\"><TR><TD>" << endnl << - "<center><b><h1>" << GetTitle() << "</h1></b></center></TD></TR></TABLE><P>" << endnl << - "<TABLE WIDTH=\"80%\" BORDER=2 cellspacing=1 BGCOLOR=\"#ffffff\"><TR><TD>" << endnl; -} - -void Action::SendFoot(Handle * h) { - (*h) << "</TABLE></TD></TR></BODY></HTML>" << endnl; -} - -String Action::GetURL(void) { - // Comme décrit plus haut, il faut renvoyer la chaîne vide si l'action est en - // mode CleanUp et a été lue. - return (hastoclean && accessed) ? "" : URL; -} - -void Action::CleanUp(void) { - hastoclean = true; -} - -void Action::Accessed(void) { - accessed = true; -} - -void Action::ShowButton(Handle * h, const String & l, const String & u) { - (*h) << "<CENTER><FORM METHOD=\"POST\" ACTION=\"/bin/" << u << "\">" << endnl << - "<INPUT TYPE=\"SUBMIT\" VALUE=\"" << l << "\">" << endnl - << "</FORM></CENTER>" << endnl; -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "BString.h"
+#include "Action.h"
+#include "HttpServ.h"
+
+Action * Action::start = 0;
+
+static int counter = 0;
+
+static String genurl(const String & u) {
+ if (u.strlen()) {
+ return u;
+ } else {
+ // Si l'url passée en paramètre est vide, on génère une URL
+ // sous la forme TmpXXXX où XXXX est une valeur qui s'incrémente.
+ return String("Tmp") + (counter++);
+ }
+}
+
+Action::Action(const String & u) : next(start), prev(0), URL(genurl(u)), hastoclean(false), accessed(false) {
+ start = this;
+ if (next) next->prev = this;
+}
+
+Action::~Action() {
+ if (start == this) {
+ start = next;
+ }
+ if (next) next->prev = prev;
+ if (prev) prev->next = next;
+}
+
+Action * Action::Look4URL(const String & URL) {
+ Action * p;
+
+// cerr << "Looking for " << URL << endl;
+ for (p = start; p; p = p->next) {
+// cerr << "p->GetURL() = " << p->GetURL() << endl;
+ if (!p->GetURL().strlen()) {
+ // Si l'action que l'on vient de tester n'a pas d'URL, elle ne sert à rien.
+ // On l'efface donc de notre liste. GetURL renvoie une chaine vide si l'action
+ // était déclarée en mode CleanUp, puis a été accédée.
+ delete p;
+ } else {
+ if (URL == p->GetURL()) return p;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Voici la skin principale. Elle nécessite un fichier 'grain.png' dans le répertoire datas
+ * et un fichier 'style.css' (fournis)
+ */
+
+void Action::SendHead(Handle * h) {
+ (*h) << "<HTML><HEAD><TITLE>" << GetTitle() << "</TITLE>" << endnl <<
+ "<META http-equiv=\"Content-Style-Type\" content=\"text/css\">" << endnl <<
+ "<LINK REL=STYLESHEET HREF=\"/image/style.css\" TYPE=\"text/css\">" << endnl <<
+ "</HEAD><BODY BGCOLOR=\"#aaaaaa\" BACKGROUND=\"/image/grain.png\">" << endnl <<
+ "<center><TABLE WIDTH=\"50%\" BORDER=3 cellspacing=1 BGCOLOR=\"#ffffff\"><TR><TD>" << endnl <<
+ "<center><b><h1>" << GetTitle() << "</h1></b></center></TD></TR></TABLE><P>" << endnl <<
+ "<TABLE WIDTH=\"80%\" BORDER=2 cellspacing=1 BGCOLOR=\"#ffffff\"><TR><TD>" << endnl;
+}
+
+void Action::SendFoot(Handle * h) {
+ (*h) << "</TABLE></TD></TR></BODY></HTML>" << endnl;
+}
+
+String Action::GetURL(void) {
+ // Comme décrit plus haut, il faut renvoyer la chaîne vide si l'action est en
+ // mode CleanUp et a été lue.
+ return (hastoclean && accessed) ? "" : URL;
+}
+
+void Action::CleanUp(void) {
+ hastoclean = true;
+}
+
+void Action::Accessed(void) {
+ accessed = true;
+}
+
+void Action::ShowButton(Handle * h, const String & l, const String & u) {
+ (*h) << "<CENTER><FORM METHOD=\"POST\" ACTION=\"/bin/" << u << "\">" << endnl <<
+ "<INPUT TYPE=\"SUBMIT\" VALUE=\"" << l << "\">" << endnl
+ << "</FORM></CENTER>" << endnl;
+}
diff --git a/lib/Buffer.cc b/lib/Buffer.cc index 216a1f6..d3e836c 100644 --- a/lib/Buffer.cc +++ b/lib/Buffer.cc @@ -1,208 +1,208 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: Buffer.cc,v 1.23 2004-04-27 11:23:29 pixel Exp $ */ - -#include <string.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Buffer.h" -#include "generic.h" - -Buffer::Buffer(bool _seekable) : Handle(-1), buffer(0), zero(0), realsiz(0), bufsiz(0), ptr(0), wptr(0), seekable(_seekable) { } - -Buffer::~Buffer() { - free(buffer); -} - -Buffer::Buffer(const Buffer & b) : Handle(-1), buffer(0), zero(b.zero), realsiz(b.realsiz), bufsiz(b.bufsiz), ptr(b.ptr), wptr(b.wptr), seekable(b.seekable) { - buffer = (Byte *) malloc(bufsiz); - memcpy(buffer, b.buffer, bufsiz); -} - -ssize_t Buffer::write(const void *buf, size_t count) throw (GeneralException) { - if (!count) { - return 0; - } - if (count + wptr > bufsiz) { - int numblocks = (count + wptr) / realloc_threshold; - int remains = (count + wptr) % realloc_threshold; - buffer = (Byte *) realloc(buffer, bufsiz = ((numblocks + (remains ? 1 : 0)) * realloc_threshold)); - } - memcpy(buffer + wptr, buf, count); - wptr += count; - - if (wptr > realsiz) { - realsiz = wptr; - } - - return count; -} - -ssize_t Buffer::read(void *buf, size_t count) throw (GeneralException) { - count = MIN(count, realsiz - ptr); - - if (!count) { - return 0; - } - - memcpy(buf, buffer + ptr, count); - ptr += count; - - if (!seekable) { - if (ptr >= realloc_threshold) { - int numblocks = (bufsiz / realloc_threshold) - (ptr / realloc_threshold); - memmove(buffer, buffer + (bufsiz - numblocks * realloc_threshold), numblocks * realloc_threshold); - ptr -= (bufsiz - numblocks * realloc_threshold); - wptr -= (bufsiz - numblocks * realloc_threshold); - realsiz -= (bufsiz - numblocks * realloc_threshold); - buffer = (Byte *) realloc(buffer, bufsiz = (numblocks * realloc_threshold)); - } - } - - return count; -} - -bool Buffer::CanRead() const { - return true; -} - -bool Buffer::CanWrite() const { - return true; -} - -String Buffer::GetName() const { - if (seekable) - return "Buffer"; - else - return "Fifo"; -} - -Buffer Buffer::operator=(const Buffer & b) { - if (b.buffer != buffer) { - free(buffer); - realsiz = b.realsiz; - ptr = b.ptr; - wptr = b.wptr; - seekable = b.seekable; - if ((bufsiz = b.bufsiz)) { - buffer = (Byte *) malloc(bufsiz); - memcpy(buffer, b.buffer, realsiz); - } else { - buffer = 0; - } - } - return *this; -} - -bool Buffer::CanWatch() const { - return false; -} - -ssize_t Buffer::GetSize() const { - return realsiz; -} - -Byte Buffer::operator[](size_t p) const { - if (p >= realsiz) { - return 0; - } else { - if (seekable) { - return buffer[p]; - } else { - return buffer[ptr + p]; - } - } -} - -Byte & Buffer::operator[](size_t p) { - p++; - if (p > bufsiz) { - int numblocks = p / realloc_threshold; - int remains = p % realloc_threshold; - buffer = (Byte *) realloc(buffer, bufsiz = ((numblocks + (remains ? 1 : 0)) * realloc_threshold)); - } - if (p > realsiz) { - memset(buffer + realsiz, 0, p - realsiz); - realsiz = p; - } - p--; - - if (seekable) { - return buffer[p]; - } else { - return buffer[ptr + p]; - } -} - -bool Buffer::CanSeek() const { - return seekable; -} - -off_t Buffer::seek(off_t off, int wheel) throw (GeneralException) { - if (!seekable) { - throw GeneralException("This buffer is a fifo, thus is not seekable"); - } - switch (wheel) { - case SEEK_SET: - ptr = off; - break; - case SEEK_CUR: - ptr += off; - break; - case SEEK_END: - ptr = realsiz + off; - break; - } - operator[](ptr); - return ptr; -} - -off_t Buffer::tell() const { - return ptr; -} - -off_t Buffer::wseek(off_t off, int wheel) throw (GeneralException) { - if (!seekable) { - throw GeneralException("This buffer is a fifo, thus is not seekable"); - } - switch (wheel) { - case SEEK_SET: - wptr = off; - break; - case SEEK_CUR: - wptr += off; - break; - case SEEK_END: - wptr = realsiz + off; - break; - } - operator[](wptr); - return wptr; -} - -off_t Buffer::wtell() const { - return wptr; -} - -void Buffer::reset() { - free(buffer); - realsiz = bufsiz = ptr = wptr = 0; -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: Buffer.cc,v 1.24 2004-11-27 21:35:19 pixel Exp $ */
+
+#include <string.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Buffer.h"
+#include "generic.h"
+
+Buffer::Buffer(bool _seekable) : Handle(-1), buffer(0), zero(0), realsiz(0), bufsiz(0), ptr(0), wptr(0), seekable(_seekable) { }
+
+Buffer::~Buffer() {
+ free(buffer);
+}
+
+Buffer::Buffer(const Buffer & b) : Handle(-1), buffer(0), zero(b.zero), realsiz(b.realsiz), bufsiz(b.bufsiz), ptr(b.ptr), wptr(b.wptr), seekable(b.seekable) {
+ buffer = (Byte *) malloc(bufsiz);
+ memcpy(buffer, b.buffer, bufsiz);
+}
+
+ssize_t Buffer::write(const void *buf, size_t count) throw (GeneralException) {
+ if (!count) {
+ return 0;
+ }
+ if (count + wptr > bufsiz) {
+ int numblocks = (count + wptr) / realloc_threshold;
+ int remains = (count + wptr) % realloc_threshold;
+ buffer = (Byte *) realloc(buffer, bufsiz = ((numblocks + (remains ? 1 : 0)) * realloc_threshold));
+ }
+ memcpy(buffer + wptr, buf, count);
+ wptr += count;
+
+ if (wptr > realsiz) {
+ realsiz = wptr;
+ }
+
+ return count;
+}
+
+ssize_t Buffer::read(void *buf, size_t count) throw (GeneralException) {
+ count = MIN(count, realsiz - ptr);
+
+ if (!count) {
+ return 0;
+ }
+
+ memcpy(buf, buffer + ptr, count);
+ ptr += count;
+
+ if (!seekable) {
+ if (ptr >= realloc_threshold) {
+ int numblocks = (bufsiz / realloc_threshold) - (ptr / realloc_threshold);
+ memmove(buffer, buffer + (bufsiz - numblocks * realloc_threshold), numblocks * realloc_threshold);
+ ptr -= (bufsiz - numblocks * realloc_threshold);
+ wptr -= (bufsiz - numblocks * realloc_threshold);
+ realsiz -= (bufsiz - numblocks * realloc_threshold);
+ buffer = (Byte *) realloc(buffer, bufsiz = (numblocks * realloc_threshold));
+ }
+ }
+
+ return count;
+}
+
+bool Buffer::CanRead() const {
+ return true;
+}
+
+bool Buffer::CanWrite() const {
+ return true;
+}
+
+String Buffer::GetName() const {
+ if (seekable)
+ return "Buffer";
+ else
+ return "Fifo";
+}
+
+Buffer Buffer::operator=(const Buffer & b) {
+ if (b.buffer != buffer) {
+ free(buffer);
+ realsiz = b.realsiz;
+ ptr = b.ptr;
+ wptr = b.wptr;
+ seekable = b.seekable;
+ if ((bufsiz = b.bufsiz)) {
+ buffer = (Byte *) malloc(bufsiz);
+ memcpy(buffer, b.buffer, realsiz);
+ } else {
+ buffer = 0;
+ }
+ }
+ return *this;
+}
+
+bool Buffer::CanWatch() const {
+ return false;
+}
+
+ssize_t Buffer::GetSize() const {
+ return realsiz;
+}
+
+Byte Buffer::operator[](size_t p) const {
+ if (p >= realsiz) {
+ return 0;
+ } else {
+ if (seekable) {
+ return buffer[p];
+ } else {
+ return buffer[ptr + p];
+ }
+ }
+}
+
+Byte & Buffer::operator[](size_t p) {
+ p++;
+ if (p > bufsiz) {
+ int numblocks = p / realloc_threshold;
+ int remains = p % realloc_threshold;
+ buffer = (Byte *) realloc(buffer, bufsiz = ((numblocks + (remains ? 1 : 0)) * realloc_threshold));
+ }
+ if (p > realsiz) {
+ memset(buffer + realsiz, 0, p - realsiz);
+ realsiz = p;
+ }
+ p--;
+
+ if (seekable) {
+ return buffer[p];
+ } else {
+ return buffer[ptr + p];
+ }
+}
+
+bool Buffer::CanSeek() const {
+ return seekable;
+}
+
+off_t Buffer::seek(off_t off, int wheel) throw (GeneralException) {
+ if (!seekable) {
+ throw GeneralException("This buffer is a fifo, thus is not seekable");
+ }
+ switch (wheel) {
+ case SEEK_SET:
+ ptr = off;
+ break;
+ case SEEK_CUR:
+ ptr += off;
+ break;
+ case SEEK_END:
+ ptr = realsiz + off;
+ break;
+ }
+ operator[](ptr);
+ return ptr;
+}
+
+off_t Buffer::tell() const {
+ return ptr;
+}
+
+off_t Buffer::wseek(off_t off, int wheel) throw (GeneralException) {
+ if (!seekable) {
+ throw GeneralException("This buffer is a fifo, thus is not seekable");
+ }
+ switch (wheel) {
+ case SEEK_SET:
+ wptr = off;
+ break;
+ case SEEK_CUR:
+ wptr += off;
+ break;
+ case SEEK_END:
+ wptr = realsiz + off;
+ break;
+ }
+ operator[](wptr);
+ return wptr;
+}
+
+off_t Buffer::wtell() const {
+ return wptr;
+}
+
+void Buffer::reset() {
+ free(buffer);
+ realsiz = bufsiz = ptr = wptr = 0;
+}
diff --git a/lib/ConfigFile.cc b/lib/ConfigFile.cc index 85cbb00..c765fae 100644 --- a/lib/ConfigFile.cc +++ b/lib/ConfigFile.cc @@ -1,43 +1,43 @@ -#include "ConfigFile.h" -#include "Regex.h" - -ConfigFile::ConfigFile(Handle * f) throw (GeneralException) { - Regex r("^\\[.*\\]$"), comment("^#.*$"), empty("^ *$"), line("^.*=.*$"); - bool started = false; - String s, section, key, value; - ConfigSectionContents contents; - int pos; - - while (!f->IsClosed()) { - (*f) >> s; - if (comment.Match(s) || empty.Match(s)) - continue; - if (r.Match(s)) { - if (!started) { - started = true; - } else { - c[section] = contents; - contents.clear(); - } - section = s.extract(1, s.strlen() - 2); - continue; - } - if (line.Match(s)) { - if (!started) { - throw GeneralException("Config file must begin with a section"); - } - pos = s.strchr('='); - key = s.extract(0, pos - 1).trim(); - value = s.extract(pos + 1).trim(); - contents[key] = value; - continue; - } - throw GeneralException("Invalid line: " + s); - } - - c[section] = contents; -} - -ConfigSectionContents & ConfigFile::operator[](String s) { - return c[s]; -} +#include "ConfigFile.h"
+#include "Regex.h"
+
+ConfigFile::ConfigFile(Handle * f) throw (GeneralException) {
+ Regex r("^\\[.*\\]$"), comment("^#.*$"), empty("^ *$"), line("^.*=.*$");
+ bool started = false;
+ String s, section, key, value;
+ ConfigSectionContents contents;
+ int pos;
+
+ while (!f->IsClosed()) {
+ (*f) >> s;
+ if (comment.Match(s) || empty.Match(s))
+ continue;
+ if (r.Match(s)) {
+ if (!started) {
+ started = true;
+ } else {
+ c[section] = contents;
+ contents.clear();
+ }
+ section = s.extract(1, s.strlen() - 2);
+ continue;
+ }
+ if (line.Match(s)) {
+ if (!started) {
+ throw GeneralException("Config file must begin with a section");
+ }
+ pos = s.strchr('=');
+ key = s.extract(0, pos - 1).trim();
+ value = s.extract(pos + 1).trim();
+ contents[key] = value;
+ continue;
+ }
+ throw GeneralException("Invalid line: " + s);
+ }
+
+ c[section] = contents;
+}
+
+ConfigSectionContents & ConfigFile::operator[](String s) {
+ return c[s];
+}
diff --git a/lib/Confirm.cc b/lib/Confirm.cc index 18e56e6..b3db8f3 100644 --- a/lib/Confirm.cc +++ b/lib/Confirm.cc @@ -1,35 +1,35 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "HttpServ.h" -#include "Confirm.h" -#include "Buffer.h" -#include "CopyJob.h" - -Confirm::Confirm(const String & t, const String & m, const String & U, Action * y, Action * n) : - Action(U), tit(t), msg(m), NYes(y), NNo(n) { } - -Task * Confirm::Do(Variables * v, Variables *, Handle * h) { - Handle * b = new Buffer; - Task * t = new CopyJob(b, h, -1, true); - SendHead(b); - (*b) << msg << "<CENTER><TABLE BORDER=0><tr><td>" << endnl << - "<FORM METHOD=\"POST\" ACTION=\"/bin/" << (NYes ? NYes->GetURL() : "start") << "\">" << endnl << - "<INPUT TYPE=\"HIDDEN\" VALUE=\"yes\" NAME=\"confirm\">" << endnl << - "<INPUT TYPE=\"SUBMIT\" VALUE=\" Oui \">" << endnl; - v->Dump(b); - (*b) << "</FORM></td><td>" << endnl << - "<FORM METHOD=\"POST\" ACTION=\"/bin/" << (NNo ? NNo->GetURL() : "start") << "\">" << endnl << - "<INPUT TYPE=\"HIDDEN\" VALUE=\"no\" NAME=\"confirm\">" << endnl << - "<INPUT TYPE=\"SUBMIT\" VALUE=\" Non \">" << endnl; - v->Dump(b); - (*b) << "</FORM></td></tr></TABLE></CENTER>" << endnl; - SendFoot(b); - Accessed(); - - return t; -} - -String Confirm::GetTitle(void) { - return tit; -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "HttpServ.h"
+#include "Confirm.h"
+#include "Buffer.h"
+#include "CopyJob.h"
+
+Confirm::Confirm(const String & t, const String & m, const String & U, Action * y, Action * n) :
+ Action(U), tit(t), msg(m), NYes(y), NNo(n) { }
+
+Task * Confirm::Do(Variables * v, Variables *, Handle * h) {
+ Handle * b = new Buffer;
+ Task * t = new CopyJob(b, h, -1, true);
+ SendHead(b);
+ (*b) << msg << "<CENTER><TABLE BORDER=0><tr><td>" << endnl <<
+ "<FORM METHOD=\"POST\" ACTION=\"/bin/" << (NYes ? NYes->GetURL() : "start") << "\">" << endnl <<
+ "<INPUT TYPE=\"HIDDEN\" VALUE=\"yes\" NAME=\"confirm\">" << endnl <<
+ "<INPUT TYPE=\"SUBMIT\" VALUE=\" Oui \">" << endnl;
+ v->Dump(b);
+ (*b) << "</FORM></td><td>" << endnl <<
+ "<FORM METHOD=\"POST\" ACTION=\"/bin/" << (NNo ? NNo->GetURL() : "start") << "\">" << endnl <<
+ "<INPUT TYPE=\"HIDDEN\" VALUE=\"no\" NAME=\"confirm\">" << endnl <<
+ "<INPUT TYPE=\"SUBMIT\" VALUE=\" Non \">" << endnl;
+ v->Dump(b);
+ (*b) << "</FORM></td></tr></TABLE></CENTER>" << endnl;
+ SendFoot(b);
+ Accessed();
+
+ return t;
+}
+
+String Confirm::GetTitle(void) {
+ return tit;
+}
diff --git a/lib/CopyJob.cc b/lib/CopyJob.cc index fc2a0ca..29c662d 100644 --- a/lib/CopyJob.cc +++ b/lib/CopyJob.cc @@ -1,84 +1,84 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "CopyJob.h" -#include "gettext.h" - -CopyJob::CopyJob(Handle * as, Handle * ad, ssize_t asiz, bool ads, bool add, int ashape) : s(as), d(ad), ds(ads), dd(add), siz(asiz), cursiz(0), r(0), w(0), tw(0), shape(ashape) { - struct timezone tz; - - s->SetNonBlock(); - d->SetNonBlock(); - WaitFor(s, W4_READING); - - if (shape > 0) { - gettimeofday(&start, &tz); - } -} - -CopyJob::~CopyJob() { - if (ds) { - delete s; - } - - if (dd) { - delete d; - } -} - -int CopyJob::Do() throw (GeneralException) { - int tr; - struct timeval now; - struct timezone tz; - - if (shape > 0) { - gettimeofday(&now, &tz); - } - - switch (current) { - case 0: - tr = siz >= 0 ? siz - cursiz : COPY_BUFSIZ; - try { - r = s->read(buffer, MIN(COPY_BUFSIZ, tr)); -// cerr << "CopyJob: read " << r << " bytes." << endl; - } - catch (IOAgain e) { - WaitFor(s, W4_READING); - Suspend(TASK_ON_HOLD); - } - if (!r) { - return TASK_DONE; - } - tw = 0; - case 1: - current = 1; - try { - w = d->write(buffer + tw, r - tw); - } - catch (IOAgain e) { - WaitFor(d, W4_WRITING); - Suspend(TASK_ON_HOLD); - } -// cerr << "CopyJob: wrote " << w << " bytes." << endl; - tw += w; - if (r != tw) { -// cerr << "CopyJob: We did expect to write a total of " << r << " bytes and we achieved " << tw << " bytes so far.\n"; - WaitFor(d, W4_WRITING); - Suspend(TASK_ON_HOLD); - } - current = 0; - } - cursiz += r; - - if (!s->IsClosed() && (siz != cursiz)) { - WaitFor(s, W4_READING); - Suspend(TASK_ON_HOLD); - } - - return TASK_DONE; -} - -String CopyJob::GetName() { - return (String(_("CopyJob from ")) + s->GetName() + _(" to ") + d->GetName()); -} - +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "CopyJob.h"
+#include "gettext.h"
+
+CopyJob::CopyJob(Handle * as, Handle * ad, ssize_t asiz, bool ads, bool add, int ashape) : s(as), d(ad), ds(ads), dd(add), siz(asiz), cursiz(0), r(0), w(0), tw(0), shape(ashape) {
+ struct timezone tz;
+
+ s->SetNonBlock();
+ d->SetNonBlock();
+ WaitFor(s, W4_READING);
+
+ if (shape > 0) {
+ gettimeofday(&start, &tz);
+ }
+}
+
+CopyJob::~CopyJob() {
+ if (ds) {
+ delete s;
+ }
+
+ if (dd) {
+ delete d;
+ }
+}
+
+int CopyJob::Do() throw (GeneralException) {
+ int tr;
+ struct timeval now;
+ struct timezone tz;
+
+ if (shape > 0) {
+ gettimeofday(&now, &tz);
+ }
+
+ switch (current) {
+ case 0:
+ tr = siz >= 0 ? siz - cursiz : COPY_BUFSIZ;
+ try {
+ r = s->read(buffer, MIN(COPY_BUFSIZ, tr));
+// cerr << "CopyJob: read " << r << " bytes." << endl;
+ }
+ catch (IOAgain e) {
+ WaitFor(s, W4_READING);
+ Suspend(TASK_ON_HOLD);
+ }
+ if (!r) {
+ return TASK_DONE;
+ }
+ tw = 0;
+ case 1:
+ current = 1;
+ try {
+ w = d->write(buffer + tw, r - tw);
+ }
+ catch (IOAgain e) {
+ WaitFor(d, W4_WRITING);
+ Suspend(TASK_ON_HOLD);
+ }
+// cerr << "CopyJob: wrote " << w << " bytes." << endl;
+ tw += w;
+ if (r != tw) {
+// cerr << "CopyJob: We did expect to write a total of " << r << " bytes and we achieved " << tw << " bytes so far.\n";
+ WaitFor(d, W4_WRITING);
+ Suspend(TASK_ON_HOLD);
+ }
+ current = 0;
+ }
+ cursiz += r;
+
+ if (!s->IsClosed() && (siz != cursiz)) {
+ WaitFor(s, W4_READING);
+ Suspend(TASK_ON_HOLD);
+ }
+
+ return TASK_DONE;
+}
+
+String CopyJob::GetName() {
+ return (String(_("CopyJob from ")) + s->GetName() + _(" to ") + d->GetName());
+}
+
diff --git a/lib/Exceptions.cc b/lib/Exceptions.cc index 06d283d..0925b21 100644 --- a/lib/Exceptions.cc +++ b/lib/Exceptions.cc @@ -1,275 +1,275 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: Exceptions.cc,v 1.33 2004-07-23 16:56:03 pixel Exp $ */ - -#include <string.h> -#include <errno.h> -#include <stddef.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#ifdef HAVE_MALLOC_H -#include <malloc.h> -#endif -#else -#ifndef __APPLE__ -#include <malloc.h> -#endif -#endif -#ifdef DEBUG -#include <iostream> -#endif -#ifdef HAVE_PIPE -#include <unistd.h> -#endif -#include "BString.h" -#include "Exceptions.h" -#include "generic.h" -#include "gettext.h" - -char GeneralException::t[BUFSIZ]; - -std::vector<String> Base::context; - -GeneralException::GeneralException(String emsg) : msg(emsg.strdup()) { - UNLOCK; -#ifdef DEBUG - printm(M_BARE, String(_("Generating a General Exception error: '")) + msg + "'.\n"); -#endif -} -GeneralException::GeneralException() : msg(0) { - UNLOCK; -#ifdef DEBUG - printm(M_BARE, String(_("Generating a General Exception error: '")) + msg + "'.\n"); -#endif -} -GeneralException::GeneralException(const GeneralException & e) : msg(strdup(e.msg)) { - UNLOCK; -#ifdef DEBUG - printm(M_BARE, String(_("Generating a General Exception error: '")) + msg + "'.\n"); -#endif -} - -GeneralException::~GeneralException() { - free(msg); -} - -TaskNotFound::TaskNotFound() : GeneralException(_("Task not found")) { } - -const char * GeneralException::GetMsg() const { - return msg; -} - -MemoryException::MemoryException(ssize_t s) { - sprintf(t, _("Failed allocating %u bytes."), s); - msg = strdup(t); -} - -IOException::IOException(String fn, op_t op, ssize_t s) { - sprintf(t, _("An error has occured while %s %u bytes on %s: %s"), op == IO_WRITE ? _("writing") : _("reading"), - s, fn.to_charp(), strerror(errno)); - msg = strdup(t); -} - -IOGeneral::IOGeneral(String fn) : GeneralException(fn) { } - -IOGeneral::IOGeneral() { } - -IOAgain::IOAgain() : IOGeneral(_("No more bytes for reading or writing.")) { -#ifdef DEBUG - printm(M_BARE, String(_("Generating an IOAgain exception: '")) + GetMsg() + "'.\n"); -#endif -} - -TaskSwitch::TaskSwitch() : GeneralException(_("Switching task in a non-tasked environnement")) { -#ifdef DEBUG - printm(M_BARE, String(_("Generating a TaskSwitch exception: '")) + GetMsg() + "'.\n"); -#endif -} - -Exit::Exit(int a_code) : GeneralException(_("Exitting with code " + a_code)), code(a_code) { -#ifdef DEBUG - printm(M_BARE, String(_("Generating an Exit exception: '")) + GetMsg() + "'.\n"); -#endif -} - -int Exit::GetCode() { - return code; -} - -char * xstrdup(const char * s) { - char * r; - - r = (char *) xmalloc(strlen(s) + 1); - strcpy(r, s); - return r; -} - -void * xmalloc(size_t s) throw (GeneralException) { - char * r; - - if (s == 0) { - return 0; - } - - if (!(r = (char *) ::malloc(s))) { - throw MemoryException(s); - } -#ifdef DEBUG -// Base::printm(M_BARE, String(_("Allocating %i bytes of memory, got it at %p\n")), s, r); -#endif - - memset(r, 0, s); - - return (void *)(r); -} - -void * xrealloc(void * ptr, size_t s) { -#ifdef DEBUG - void * r = realloc(ptr, s); - Base::printm(M_BARE, String(_("Reallocating pointer at %p for %i bytes, now at %p\n")), ptr, s, r); - return r; -#else - return realloc(ptr, s); -#endif -} - -void xfree(unsigned char *& p) { -#ifdef DEBUG -// Base::printm(M_BARE, String(_("Freeing pointer at %p\n")), p); -#endif - if (p) { - ::free(p); - p = 0; - } -} - -#ifdef HAVE_PIPE -int xpipe(int * p, int flag) throw (GeneralException) { - if (pipe(p)) { - throw GeneralException(String(_("Error creating pipe: ")) + strerror(errno)); - } - - return p[flag]; -} -#else -int xpipe(int *, int) throw (GeneralException) { - throw GeneralException(_("Function pipe() not supported by this system.\n")); -} -#endif - -#ifdef HAVE_FORK -pid_t xfork() throw (GeneralException) { - pid_t p; - - p = fork(); - - if (p == -1) { - throw GeneralException(_("Was not able to fork().\n")); - } - - return p; -} -#else -pid_t xfork() throw (GeneralException) { - throw GeneralException(_("Function fork() not supported by this system.\n")); -} -#endif - -void xexit(int status) throw (GeneralException) { - throw Exit(status); -} - -void xexception(const String & err) throw (GeneralException) { - throw GeneralException(err); -} - -char * Base::strdup(const char * s) { - return xstrdup(s); -} - -void * Base::malloc(ssize_t s) { - return xmalloc(s); -} - -void * Base::realloc(void * p, size_t s) { - return xrealloc(p, s); -} - -void * Base::calloc(size_t n, size_t s) { - return xmalloc(n * s); -} - -void * Base::operator new(size_t s) { -#ifdef DEBUG - printm(M_BARE, _("Operator new(s) called. Allocating memory.\n")); -#endif - return xmalloc(s); -} - -void * Base::operator new(size_t s, void * p) { -#ifdef DEBUG - printm(M_BARE, String(_("Operator new(s, p) called with p = %p and s = %i. Erasing memory.\n")), p, s); -#endif - return memset(p, 0, s); -} - -void Base::operator delete(void * p) { -#ifdef DEBUG - printm(M_BARE, _("Operator delete(p) called. Freeing memory.\n")); -#endif - free(p); -} - -int Base::pipe(int * p, int flag) { - return xpipe(p, flag); -} - -pid_t Base::fork() { - return xfork(); -} - -void Base::exit(int status) { - xexit(status); -} - -void Base::flushcontext() { - context.clear(); -} - -void Base::pushcontext(const String & c) { - context.push_back(c); -} - -void Base::popcontext() { - context.pop_back(); -} - -void Base::exception(const String & err) { - int c; - std::vector<String>::iterator i; - printm(M_ERROR, "Error detected, showing context.\n"); - for (i = context.begin(), c = 0; i != context.end(); i++, c++) { - printm(M_ERROR, " (%i) - " + *i + "\n", c); - } - - printm(M_ERROR, " Error description: " + err); - - xexception(err); -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: Exceptions.cc,v 1.34 2004-11-27 21:35:19 pixel Exp $ */
+
+#include <string.h>
+#include <errno.h>
+#include <stddef.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#else
+#ifndef __APPLE__
+#include <malloc.h>
+#endif
+#endif
+#ifdef DEBUG
+#include <iostream>
+#endif
+#ifdef HAVE_PIPE
+#include <unistd.h>
+#endif
+#include "BString.h"
+#include "Exceptions.h"
+#include "generic.h"
+#include "gettext.h"
+
+char GeneralException::t[BUFSIZ];
+
+std::vector<String> Base::context;
+
+GeneralException::GeneralException(String emsg) : msg(emsg.strdup()) {
+ UNLOCK;
+#ifdef DEBUG
+ printm(M_BARE, String(_("Generating a General Exception error: '")) + msg + "'.\n");
+#endif
+}
+GeneralException::GeneralException() : msg(0) {
+ UNLOCK;
+#ifdef DEBUG
+ printm(M_BARE, String(_("Generating a General Exception error: '")) + msg + "'.\n");
+#endif
+}
+GeneralException::GeneralException(const GeneralException & e) : msg(strdup(e.msg)) {
+ UNLOCK;
+#ifdef DEBUG
+ printm(M_BARE, String(_("Generating a General Exception error: '")) + msg + "'.\n");
+#endif
+}
+
+GeneralException::~GeneralException() {
+ free(msg);
+}
+
+TaskNotFound::TaskNotFound() : GeneralException(_("Task not found")) { }
+
+const char * GeneralException::GetMsg() const {
+ return msg;
+}
+
+MemoryException::MemoryException(ssize_t s) {
+ sprintf(t, _("Failed allocating %u bytes."), s);
+ msg = strdup(t);
+}
+
+IOException::IOException(String fn, op_t op, ssize_t s) {
+ sprintf(t, _("An error has occured while %s %u bytes on %s: %s"), op == IO_WRITE ? _("writing") : _("reading"),
+ s, fn.to_charp(), strerror(errno));
+ msg = strdup(t);
+}
+
+IOGeneral::IOGeneral(String fn) : GeneralException(fn) { }
+
+IOGeneral::IOGeneral() { }
+
+IOAgain::IOAgain() : IOGeneral(_("No more bytes for reading or writing.")) {
+#ifdef DEBUG
+ printm(M_BARE, String(_("Generating an IOAgain exception: '")) + GetMsg() + "'.\n");
+#endif
+}
+
+TaskSwitch::TaskSwitch() : GeneralException(_("Switching task in a non-tasked environnement")) {
+#ifdef DEBUG
+ printm(M_BARE, String(_("Generating a TaskSwitch exception: '")) + GetMsg() + "'.\n");
+#endif
+}
+
+Exit::Exit(int a_code) : GeneralException(_("Exitting with code " + a_code)), code(a_code) {
+#ifdef DEBUG
+ printm(M_BARE, String(_("Generating an Exit exception: '")) + GetMsg() + "'.\n");
+#endif
+}
+
+int Exit::GetCode() {
+ return code;
+}
+
+char * xstrdup(const char * s) {
+ char * r;
+
+ r = (char *) xmalloc(strlen(s) + 1);
+ strcpy(r, s);
+ return r;
+}
+
+void * xmalloc(size_t s) throw (GeneralException) {
+ char * r;
+
+ if (s == 0) {
+ return 0;
+ }
+
+ if (!(r = (char *) ::malloc(s))) {
+ throw MemoryException(s);
+ }
+#ifdef DEBUG
+// Base::printm(M_BARE, String(_("Allocating %i bytes of memory, got it at %p\n")), s, r);
+#endif
+
+ memset(r, 0, s);
+
+ return (void *)(r);
+}
+
+void * xrealloc(void * ptr, size_t s) {
+#ifdef DEBUG
+ void * r = realloc(ptr, s);
+ Base::printm(M_BARE, String(_("Reallocating pointer at %p for %i bytes, now at %p\n")), ptr, s, r);
+ return r;
+#else
+ return realloc(ptr, s);
+#endif
+}
+
+void xfree(unsigned char *& p) {
+#ifdef DEBUG
+// Base::printm(M_BARE, String(_("Freeing pointer at %p\n")), p);
+#endif
+ if (p) {
+ ::free(p);
+ p = 0;
+ }
+}
+
+#ifdef HAVE_PIPE
+int xpipe(int * p, int flag) throw (GeneralException) {
+ if (pipe(p)) {
+ throw GeneralException(String(_("Error creating pipe: ")) + strerror(errno));
+ }
+
+ return p[flag];
+}
+#else
+int xpipe(int *, int) throw (GeneralException) {
+ throw GeneralException(_("Function pipe() not supported by this system.\n"));
+}
+#endif
+
+#ifdef HAVE_FORK
+pid_t xfork() throw (GeneralException) {
+ pid_t p;
+
+ p = fork();
+
+ if (p == -1) {
+ throw GeneralException(_("Was not able to fork().\n"));
+ }
+
+ return p;
+}
+#else
+pid_t xfork() throw (GeneralException) {
+ throw GeneralException(_("Function fork() not supported by this system.\n"));
+}
+#endif
+
+void xexit(int status) throw (GeneralException) {
+ throw Exit(status);
+}
+
+void xexception(const String & err) throw (GeneralException) {
+ throw GeneralException(err);
+}
+
+char * Base::strdup(const char * s) {
+ return xstrdup(s);
+}
+
+void * Base::malloc(ssize_t s) {
+ return xmalloc(s);
+}
+
+void * Base::realloc(void * p, size_t s) {
+ return xrealloc(p, s);
+}
+
+void * Base::calloc(size_t n, size_t s) {
+ return xmalloc(n * s);
+}
+
+void * Base::operator new(size_t s) {
+#ifdef DEBUG
+ printm(M_BARE, _("Operator new(s) called. Allocating memory.\n"));
+#endif
+ return xmalloc(s);
+}
+
+void * Base::operator new(size_t s, void * p) {
+#ifdef DEBUG
+ printm(M_BARE, String(_("Operator new(s, p) called with p = %p and s = %i. Erasing memory.\n")), p, s);
+#endif
+ return memset(p, 0, s);
+}
+
+void Base::operator delete(void * p) {
+#ifdef DEBUG
+ printm(M_BARE, _("Operator delete(p) called. Freeing memory.\n"));
+#endif
+ free(p);
+}
+
+int Base::pipe(int * p, int flag) {
+ return xpipe(p, flag);
+}
+
+pid_t Base::fork() {
+ return xfork();
+}
+
+void Base::exit(int status) {
+ xexit(status);
+}
+
+void Base::flushcontext() {
+ context.clear();
+}
+
+void Base::pushcontext(const String & c) {
+ context.push_back(c);
+}
+
+void Base::popcontext() {
+ context.pop_back();
+}
+
+void Base::exception(const String & err) {
+ int c;
+ std::vector<String>::iterator i;
+ printm(M_ERROR, "Error detected, showing context.\n");
+ for (i = context.begin(), c = 0; i != context.end(); i++, c++) {
+ printm(M_ERROR, " (%i) - " + *i + "\n", c);
+ }
+
+ printm(M_ERROR, " Error description: " + err);
+
+ xexception(err);
+}
diff --git a/lib/Form.cc b/lib/Form.cc index fedfc3e..122f0a5 100644 --- a/lib/Form.cc +++ b/lib/Form.cc @@ -1,65 +1,65 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Form.h" -#include "HttpServ.h" -#include "Buffer.h" -#include "CopyJob.h" - -Form::Form(const String & titre, const String & url, const String & inv, String * names, String * invs, - String * defaults, String ** lists, String ** descs, int nb, Action * na) : - Action(url), tit(titre), iv(inv), nms(names), ivs(invs), defs(defaults), lsts(lists), dscs(descs), n(nb), Next(na) { } - -String Form::GetTitle(void) { - return tit; -} - -Task * Form::Do(Variables * v, Variables *, Handle * h) { - Handle * b = new Buffer(); - Task * t = new CopyJob(b, h, -1, true); - SendHead(b); - - (*b) << -"<center>" << endnl << -"<form ACTION=\"/bin/" << (Next ? Next->GetURL() : "start") << "\" METHOD=POST>" << endnl; - - v->Dump(b); - - (*b) << -"<table BORDER=0 CELLSPACING=0 BGCOLOR=\"#000000\"><tr><td>" << endnl << -"<table BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=\"300\" BGCOLOR=\"#FFFFCC\">" << endnl << -"<tr><td ALIGN=CENTER WIDTH=\"100%\" BGCOLOR=\"#000000\"><b><font FACE=\"arial,helvetica\" COLOR=\"#FFFFFF\">" << endnl << -iv << endnl << -"</font></b></td></tr>" << endnl; - - for (int i = 0; i < n; i++) { - (*b) << -"<tr><td>" << ivs[i] << "</td></tr>" << endnl; - if (lsts[i]) { - String * s, * t; - (*b) << -"<tr><td><select NAME=\"" << nms[i] << "\">" << endnl; - for (s = lsts[i], t = dscs[i]; s->strlen(); s++, t++) { - (*b) << -"<option VALUE=\"" << *s << "\">" << *t << "</option>" << endnl; - } - (*b) << -"</select></td></tr>" << endnl; - } else { - (*b) << -"<tr><td><input TYPE=\"text\" NAME=\"" << nms[i] << "\" VALUE=\"" << defs[i] << "\" size=40></tr></td>" << endnl; - } - } - - (*b) << - -"<tr><td ALIGN=\"center\"><input TYPE=\"submit\" VALUE=\" Ok \"></td></tr>" << endnl << -"</table></td></tr></table></form></center>" << endnl; - - SendFoot(b); - - Accessed(); - - return t; -} - +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Form.h"
+#include "HttpServ.h"
+#include "Buffer.h"
+#include "CopyJob.h"
+
+Form::Form(const String & titre, const String & url, const String & inv, String * names, String * invs,
+ String * defaults, String ** lists, String ** descs, int nb, Action * na) :
+ Action(url), tit(titre), iv(inv), nms(names), ivs(invs), defs(defaults), lsts(lists), dscs(descs), n(nb), Next(na) { }
+
+String Form::GetTitle(void) {
+ return tit;
+}
+
+Task * Form::Do(Variables * v, Variables *, Handle * h) {
+ Handle * b = new Buffer();
+ Task * t = new CopyJob(b, h, -1, true);
+ SendHead(b);
+
+ (*b) <<
+"<center>" << endnl <<
+"<form ACTION=\"/bin/" << (Next ? Next->GetURL() : "start") << "\" METHOD=POST>" << endnl;
+
+ v->Dump(b);
+
+ (*b) <<
+"<table BORDER=0 CELLSPACING=0 BGCOLOR=\"#000000\"><tr><td>" << endnl <<
+"<table BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=\"300\" BGCOLOR=\"#FFFFCC\">" << endnl <<
+"<tr><td ALIGN=CENTER WIDTH=\"100%\" BGCOLOR=\"#000000\"><b><font FACE=\"arial,helvetica\" COLOR=\"#FFFFFF\">" << endnl <<
+iv << endnl <<
+"</font></b></td></tr>" << endnl;
+
+ for (int i = 0; i < n; i++) {
+ (*b) <<
+"<tr><td>" << ivs[i] << "</td></tr>" << endnl;
+ if (lsts[i]) {
+ String * s, * t;
+ (*b) <<
+"<tr><td><select NAME=\"" << nms[i] << "\">" << endnl;
+ for (s = lsts[i], t = dscs[i]; s->strlen(); s++, t++) {
+ (*b) <<
+"<option VALUE=\"" << *s << "\">" << *t << "</option>" << endnl;
+ }
+ (*b) <<
+"</select></td></tr>" << endnl;
+ } else {
+ (*b) <<
+"<tr><td><input TYPE=\"text\" NAME=\"" << nms[i] << "\" VALUE=\"" << defs[i] << "\" size=40></tr></td>" << endnl;
+ }
+ }
+
+ (*b) <<
+
+"<tr><td ALIGN=\"center\"><input TYPE=\"submit\" VALUE=\" Ok \"></td></tr>" << endnl <<
+"</table></td></tr></table></form></center>" << endnl;
+
+ SendFoot(b);
+
+ Accessed();
+
+ return t;
+}
+
diff --git a/lib/GMPString.cc b/lib/GMPString.cc index be39e38..5fb76c8 100644 --- a/lib/GMPString.cc +++ b/lib/GMPString.cc @@ -1,30 +1,30 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef HAVE_GMP -#include <gmpxx.h> -#include "GMPString.h" - -GMPString::GMPString(const GMPString & s) : str(s.str) { -} - -GMPString::GMPString(const mpz_class & z) { - gmp_asprintf(&str, "%Zd", z.get_mpz_t()); -} - -GMPString::GMPString(const mpq_class & q) { - gmp_asprintf(&str, "%Qd", q.get_mpq_t()); -} - -GMPString::GMPString(const mpf_class & f) { - gmp_asprintf(&str, "%Ff", f.get_mpf_t()); -} - -GMPString::operator String() const { - return String(str); -} - -GMPString::~GMPString() { -} - -#endif +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef HAVE_GMP
+#include <gmpxx.h>
+#include "GMPString.h"
+
+GMPString::GMPString(const GMPString & s) : str(s.str) {
+}
+
+GMPString::GMPString(const mpz_class & z) {
+ gmp_asprintf(&str, "%Zd", z.get_mpz_t());
+}
+
+GMPString::GMPString(const mpq_class & q) {
+ gmp_asprintf(&str, "%Qd", q.get_mpq_t());
+}
+
+GMPString::GMPString(const mpf_class & f) {
+ gmp_asprintf(&str, "%Ff", f.get_mpf_t());
+}
+
+GMPString::operator String() const {
+ return String(str);
+}
+
+GMPString::~GMPString() {
+}
+
+#endif
diff --git a/lib/Handle.cc b/lib/Handle.cc index c38f47e..bbd3e04 100644 --- a/lib/Handle.cc +++ b/lib/Handle.cc @@ -1,658 +1,658 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: Handle.cc,v 1.71 2004-07-23 16:56:03 pixel Exp $ */ - -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "generic.h" - -#if defined WORDS_BIGENDIAN -#if defined HAVE_BYTESWAP_H -#include <byteswap.h> -#else -inline Uint16 bswap_16(Uint16 w) { - return (w >> 8) | (w << 8); -} - -inline Uint32 bswap_32(Uint32 w) { - return (w >> 24) | ((w >> 8) & 0x0000ff00) | ((w << 8) & 0x00ff0000) | (w << 24); -} -#endif -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#else -#include <io.h> -#endif - -#ifndef _WIN32 -#include <sys/mman.h> -#endif - -#include "Handle.h" -#include "gettext.h" - -enum { - DEFLATE, - INFLATE -}; - -Handle::Handle(const Handle & nh) : itell(0), hFile(0), h(nh.h >= 0 ? dup(nh.h) : nh.h), closed(nh.closed), nonblock(nh.closed), zfile(0), z(0), hMapObject(0), mapped(0) -{ -#ifdef DEBUG - printm(M_INFO, String(_("Duplication of handle ")) + nh.h + _(" to ") + h + "\n"); -#endif - if ((h >= 0) && (nh.z)) { - SetZ(nh.z); - } -} - -Handle::~Handle() { -#ifdef DEBUG - printm(M_INFO, String(_("Destroying handle ")) + h + "\n"); -#endif - close(); -} - -Handle::Handle(int nh) : h(nh), closed(false), nonblock(false), zfile(0), z(0), hMapObject(0), mapped(0) -{ -#ifdef DEBUG - printm(M_INFO, String(_("Initialising handle ")) + h + "\n"); -#endif -} - -int Handle::GetHandle() { - return h; -} - -void * Handle::GetHFile() { - return hFile; -} - -int Handle::GetHandle() const { - return h; -} - -ssize_t Handle::write(const void *cbuf, size_t count) throw (GeneralException) { - ssize_t r, tr = 0; - bool done, full = false; - const char * buf = (const char *)cbuf; - - if (closed) { - throw IOGeneral("Unable to write: handle `" + GetName() + "' is closed."); - } - - if (!count) - return 0; - - do { - done = true; - errno = 0; - if ((r = uwrite(buf, count)) < 0) { - if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) { - // Avant de déclarer une erreur, on vérifie si ce n'est pas un - // problème lié au fait qu'il n'y a plus de place libre. Cela peut - // arriver si l'on agit sur un pipe ou un handle. Nous - // attendons encore une fois avant de déclarer l'erreur, - // grace au drapeau full. - if (full) { - throw IOException(GetName(), IO_WRITE, count); - } else { - done = false; - full = true; - if (nonblock) { -#ifdef DEBUG - printm(M_INFO, _("write: throwing IOAgain for handle ") + GetName() + "\n"); -#endif - throw IOAgain(); - } else { -#ifdef HAVE_SLEEP - sleep(1); -#endif - } - } - } else { - throw IOException(GetName(), IO_WRITE, count); - } - } else if (((size_t) r) != count) { - if (nonblock) { - return r; - } - full = done = false; - buf += r; - tr += r; - } - } while (!done); - - return r + tr; -} - -ssize_t Handle::read(void *buf, size_t count) throw (GeneralException) { - ssize_t r; - - if (closed) { - throw IOGeneral("Unable to read: handle `" + GetName() + "' is closed."); - } - - if (!count) - return 0; - -#ifdef FULLDEBUG - printm(M_INFO, String(_("read: reading ")) + count + _(" bytes from handle ") + GetHandle() + "\n"); -#endif - - errno = 0; - while ((r = uread(buf, count)) < 0) { - if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) { - // Avant de déclarer une erreur, on vérifie si ce n'est pas un - // problème lié au fait qu'il n'y a plus d'octets. - if (nonblock) { -#ifdef DEBUG - printm(M_INFO, _("read: throwing IOAgain for handle ") + GetName() + "\n"); -#endif - throw IOAgain(); - } - } else { - throw IOException(GetName(), IO_READ, count); - } - } - - if (!r) { - close(); - } - - return r; -} - -bool Handle::IsClosed(void) const { - return closed; -} - -bool Handle::IsNonBlock(void) const { - return nonblock; -} - -void Handle::SetNonBlock(void) { -#ifdef HAVE_FCNTL - if ((h >= 0) || !nonblock) { - fcntl(h, F_SETFL, O_NONBLOCK); - } - nonblock = true; -#endif -} - -Handle & operator<<(Handle & h, const String & s) { - const char * p; - - p = s.to_charp(); - h.write(p, strlen(p)); - - return h; -} - -Handle & operator>>(Handle & h, String & s) { - char t[BUFSIZ]; - int i = 0, r; - - while ((r = h.read(&(t[i]), 1)) && (i != (BUFSIZ - 1))) { - // Il y a souvent des \r\n dans les sockets par exemple, - // ou bien en lisant des fichiers au format MS-DOS. On - // ignore le \r pour ne garder que le \n, standard sous Unix. - if (t[i] == '\r') { - continue; - } - if (t[i] == '\n') { - break; - } else { - i++; - } - } - - t[i] = '\0'; - s = t; - return h; -} - -void Handle::close() throw (GeneralException) { - if (IsClosed()) { - return; - } - - Flush(); - - if (h >= 0) { - if (z >= 10) { - int err; - if (c == DEFLATE) { - err = deflateEnd(&zstrm); - if (err != Z_OK) { - throw GeneralException(String(_("Error during deflateEnd: ")) + zstrm.msg); - } - } else { - err = inflateEnd(&zstrm); - if (err != Z_OK) { - throw GeneralException(String(_("Error during inflateEnd: ")) + zstrm.msg); - } - } - err = ::close(h); - if (err) { - throw GeneralException(String(_("Error during (zstream) close: ")) + strerror(errno)); - } - } else if (z) { -#ifdef DEBUG - printm(M_INFO, String(_("Performing gzclose on handle ")) + h + "\n"); -#endif - int err = gzclose(zfile); -#ifdef DEBUG - printm(M_INFO, String(_("gzclose returned ")) + err + "\n"); -#endif - if (err) { - if (err == Z_ERRNO) { - throw GeneralException(String(_("Error during close: ")) + strerror(errno)); - } else { - throw GeneralException(String(_("Error in zlib during gzclose: ")) + gzerror(zfile, &err)); - } - } - } else { - if (!hFile) { - int err = ::close(h); - if (err) { - throw GeneralException(String(_("Error during close: ")) + strerror(errno)); - } - } - } -#if defined (_WIN32) && !defined (NO_HFILE) - if (hFile) { - CloseHandle(hFile); - hFile = 0; - } -#endif - } - - if (mapped) { - munmap(); - } - - h = -1; - closed = 1; -} - -bool Handle::CanRead(void) const { - return false; -} - -bool Handle::CanWrite(void) const { - return false; -} - -String Handle::GetName(void) const { - return _("Bare Handle - should not happend"); -} - -ssize_t Handle::GetSize(void) const { - return -1; -} - -time_t Handle::GetModif(void) const { - return -1; -} - -bool Handle::CanWatch(void) const { - return true; -} - -int Handle::Dup() const throw (GeneralException) { - int d; - - if ((d = dup(h)) < 0) { - throw IOGeneral(String(_("Error dupping file `")) + GetName() + _("' (handle ") + h + "): " + strerror(errno) + " (" + errno + ")"); - } - return d; -} - -void Handle::SetZ(int az) throw (GeneralException) { - if (z) { - throw GeneralException(_("Can't SetZ a Handle twice.")); - } - if (h < 0) { - throw GeneralException(_("Can't SetZ a virtual Handle.")); - } - if (az >= 10) { -#ifdef DEBUG - printm(M_INFO, _("Setting up zstream using inflate/deflate...\n")); -#endif - int err; - zstrm.zalloc = Z_NULL; - zstrm.zfree = Z_NULL; - if (CanWrite()) { - c = DEFLATE; - err = deflateInit(&zstrm, az - 10); - if (err != Z_OK) { - throw GeneralException(String(_("Error in deflateInit: ")) + zstrm.msg); - } - } else { - c = INFLATE; - zstrm.next_in = 0; - zstrm.avail_in = 0; - err = inflateInit(&zstrm); - if (err != Z_OK) { - throw GeneralException(String(_("Error in inflateInit: ")) + zstrm.msg); - } - } - } else if (az) { - char format[5]; - int index = 0; - if (CanRead()) { - format[index++] = 'r'; - } - if (CanWrite()) { - format[index++] = 'w'; - } - format[index++] = (char) (az + '0'); - format[index++] = 'b'; - format[index] = 0; -#ifdef FULLDEBUG - printm(M_INFO, String(_("Performing gzdopen on handle ")) + h + _(" with mode \"") + format + "\"\n"); -#endif - if (!(zfile = gzdopen(h, format))) { - throw GeneralException(String(_("Was not able to gzdopen: ")) + strerror(errno)); - } - z = az; - } -} - -ssize_t Handle::uwrite(const void * buf, size_t count) throw (GeneralException) { - if (z >= 10) { - } else if (z) { -#ifdef FULLDEBUG - printm(M_INFO, String(_("Performing gzwrite of ")) + count + _(" byte(s) for handle ") + h + "\n"); -#endif -#ifdef HAVE_WD_ZLIB - int err = gzwrite(zfile, buf, count); -#else - int err = gzwrite(zfile, (char *) buf, count); -#endif - if (err == 0) { - const char * m = gzerror(zfile, &err); - if (err == Z_ERRNO) { - return -1; - } else { - throw GeneralException(String(_("Error in zlib during gzwrite: ")) + m); - } - } - itell += err; - return err; - } else { - itell += count = ::write(h, buf, count); - return count; - } -} - -ssize_t Handle::uread(void * buf, size_t count) { - if (z >= 10) { - } if (z) { -#ifdef DEBUG - printm(M_BARE, String(_("Performing gzread of ")) + count + _(" byte(s) for handle ") + h + "\n"); -#endif - int err = gzread(zfile, buf, count); - if (err == -1) { - gzerror(zfile, &err); - if (err == Z_ERRNO) { - return -1; - } else { - return 0; - } - } - itell += err; - return err; - } else { -#if defined (_WIN32) && !defined (NO_HFILE) - if (hFile) { - DWORD rcount; - if (!ReadFile(hFile, buf, count, &rcount, 0)) { - // Error.. - } - itell += count = rcount; - } else -#endif - itell += count = ::read(h, buf, count); - return count; - } -} - -off_t Handle::tell() const { - if (z) { - return gztell(zfile); - } else { - return itell; - } -} - -bool Handle::CanSeek() const { - return 0; -} - -off_t Handle::seek(off_t offset, int whence) throw(GeneralException) { - if (z) { - return itell = gzseek(zfile, offset, whence); - } else { - throw IOGeneral(_("Handle ") + GetName() + _(" can't seek")); - } -} - -Uint8 Handle::readU8() { - Uint8 r; - read(&r, 1); - return r; -} - -Uint16 Handle::readU16() { - Uint16 r; - read(&r, 2); -#ifdef WORDS_BIGENDIAN - return bswap_16(r); -#else - return r; -#endif -} - -Uint32 Handle::readU32() { - Uint32 r; - read(&r, 4); -#ifdef WORDS_BIGENDIAN - return bswap_32(r); -#else - return r; -#endif -} - -void Handle::writeU8(Uint8 v) { - write(&v, 1); -} - -void Handle::writeU16(Uint16 v) { -#ifdef WORDS_BIGENDIAN - Uint16 t = bswap_16(v); - write(&t, 2); -#else - write(&v, 2); -#endif -} - -void Handle::writeU32(Uint32 v) { -#ifdef WORDS_BIGENDIAN - Uint32 t = bswap_32(v); - write(&t, 4); -#else - write(&v, 4); -#endif -} - -void Handle::copyto(Handle * dest, ssize_t s) { - copy(this, dest, s); -} - -void Handle::copyfrom(Handle * src, ssize_t s) { - copy(src, this, s); -} - -void copyone(Handle * s, Handle * d, ssize_t size) { - long i; - unsigned char c; - long r; - - if (size < 0) - size = s->GetSize(); - - for (i = 0; (i < size) || (size < 0); i++) { - r = s->read(&c, 1); - if (r == 0) { - break; - } - d->write(&c, 1); - } -} - -#define BSIZE 20480 - -void copy(Handle * s, Handle * d, ssize_t size) { - long i; - static unsigned char b[BSIZE]; - long r; - - if (size < 0) - size = s->GetSize(); - - LOCK; - - while (size) { - if ((size > BSIZE) || (size < 0)) { - r = s->read(b, BSIZE); - if (r) - d->write(b, r); - } else { - r = s->read(b, size); - if (r) - d->write(b, r); - } - if (!r) - break; - if (size > 0) - size -= r; - } - - UNLOCK; -} - -void Handle::Flush() { - if (!CanWrite()) - return; - if (h < 0) - return; - if (z >= 10) { - - } else if (z) { - gzflush(&z, Z_FULL_FLUSH); - } else { -#ifdef HAVE_FSYNC - fsync(h); -#endif - } -} - -void * Handle::mmap(off_t offset, size_t length) throw (GeneralException) { - void * r; - - if (h == -1) { - throw GeneralException("Can't mmap() a virtual handle"); - } -#ifdef _WIN32 - if (!hFile) { - throw GeneralException("Can't mmap() a non-hFile handle under windows"); - } -#endif - if (mapped) { - throw GeneralException("Handle already mmap()ped"); - } - mapped = true; - if (length == -1) { - length = GetSize(); - } - maplength = length; -#ifndef _WIN32 - r = ::mmap(0, length, (CanRead() ? PROT_READ : 0) | (CanWrite() ? PROT_WRITE : 0), MAP_SHARED, h, offset); - if (!r) { - throw GeneralException(String("Was not able to mmap(): ") + strerror(errno)); - } -#else - hMapObject = CreateFileMapping( - hFile, - 0, - CanWrite() ? PAGE_READWRITE : PAGE_READONLY, - 0, - length, - GetName().to_charp()); - if (hMapObject != NULL) { - r = MapViewOfFile( - hMapObject, - CanWrite() ? FILE_MAP_WRITE : FILE_MAP_READ, - 0, - offset, - length); - if (!r) { - CloseHandle(hMapObject); - throw GeneralException("Was not able to MapViewOfFile()"); - } - } else { - throw GeneralException("Was not able to CreateFileMapping()"); - } -#endif - - mappedarea = r; - - return r; -} - -void Handle::munmap() throw (GeneralException) { - if (!mapped) { - throw GeneralException("Can't munmap, was not mapped"); - } -#ifndef _WIN32 - if (::munmap(mappedarea, maplength)) { - throw GeneralException(String("Was not able to munmap(): ") + strerror(errno)); - } -#else - if (!UnmapViewOfFile(mappedarea)) { - throw GeneralException("Was not able to UnmapViewOfFile()"); - } - CloseHandle(hMapObject); -#endif - mapped = false; - mappedarea = 0; - maplength = 0; -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: Handle.cc,v 1.72 2004-11-27 21:35:19 pixel Exp $ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "generic.h"
+
+#if defined WORDS_BIGENDIAN
+#if defined HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+inline Uint16 bswap_16(Uint16 w) {
+ return (w >> 8) | (w << 8);
+}
+
+inline Uint32 bswap_32(Uint32 w) {
+ return (w >> 24) | ((w >> 8) & 0x0000ff00) | ((w << 8) & 0x00ff0000) | (w << 24);
+}
+#endif
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/mman.h>
+#endif
+
+#include "Handle.h"
+#include "gettext.h"
+
+enum {
+ DEFLATE,
+ INFLATE
+};
+
+Handle::Handle(const Handle & nh) : itell(0), hFile(0), h(nh.h >= 0 ? dup(nh.h) : nh.h), closed(nh.closed), nonblock(nh.closed), zfile(0), z(0), hMapObject(0), mapped(0)
+{
+#ifdef DEBUG
+ printm(M_INFO, String(_("Duplication of handle ")) + nh.h + _(" to ") + h + "\n");
+#endif
+ if ((h >= 0) && (nh.z)) {
+ SetZ(nh.z);
+ }
+}
+
+Handle::~Handle() {
+#ifdef DEBUG
+ printm(M_INFO, String(_("Destroying handle ")) + h + "\n");
+#endif
+ close();
+}
+
+Handle::Handle(int nh) : h(nh), closed(false), nonblock(false), zfile(0), z(0), hMapObject(0), mapped(0)
+{
+#ifdef DEBUG
+ printm(M_INFO, String(_("Initialising handle ")) + h + "\n");
+#endif
+}
+
+int Handle::GetHandle() {
+ return h;
+}
+
+void * Handle::GetHFile() {
+ return hFile;
+}
+
+int Handle::GetHandle() const {
+ return h;
+}
+
+ssize_t Handle::write(const void *cbuf, size_t count) throw (GeneralException) {
+ ssize_t r, tr = 0;
+ bool done, full = false;
+ const char * buf = (const char *)cbuf;
+
+ if (closed) {
+ throw IOGeneral("Unable to write: handle `" + GetName() + "' is closed.");
+ }
+
+ if (!count)
+ return 0;
+
+ do {
+ done = true;
+ errno = 0;
+ if ((r = uwrite(buf, count)) < 0) {
+ if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) {
+ // Avant de déclarer une erreur, on vérifie si ce n'est pas un
+ // problème lié au fait qu'il n'y a plus de place libre. Cela peut
+ // arriver si l'on agit sur un pipe ou un handle. Nous
+ // attendons encore une fois avant de déclarer l'erreur,
+ // grace au drapeau full.
+ if (full) {
+ throw IOException(GetName(), IO_WRITE, count);
+ } else {
+ done = false;
+ full = true;
+ if (nonblock) {
+#ifdef DEBUG
+ printm(M_INFO, _("write: throwing IOAgain for handle ") + GetName() + "\n");
+#endif
+ throw IOAgain();
+ } else {
+#ifdef HAVE_SLEEP
+ sleep(1);
+#endif
+ }
+ }
+ } else {
+ throw IOException(GetName(), IO_WRITE, count);
+ }
+ } else if (((size_t) r) != count) {
+ if (nonblock) {
+ return r;
+ }
+ full = done = false;
+ buf += r;
+ tr += r;
+ }
+ } while (!done);
+
+ return r + tr;
+}
+
+ssize_t Handle::read(void *buf, size_t count) throw (GeneralException) {
+ ssize_t r;
+
+ if (closed) {
+ throw IOGeneral("Unable to read: handle `" + GetName() + "' is closed.");
+ }
+
+ if (!count)
+ return 0;
+
+#ifdef FULLDEBUG
+ printm(M_INFO, String(_("read: reading ")) + count + _(" bytes from handle ") + GetHandle() + "\n");
+#endif
+
+ errno = 0;
+ while ((r = uread(buf, count)) < 0) {
+ if ((!errno) || (errno == EAGAIN) || (errno == EINTR)) {
+ // Avant de déclarer une erreur, on vérifie si ce n'est pas un
+ // problème lié au fait qu'il n'y a plus d'octets.
+ if (nonblock) {
+#ifdef DEBUG
+ printm(M_INFO, _("read: throwing IOAgain for handle ") + GetName() + "\n");
+#endif
+ throw IOAgain();
+ }
+ } else {
+ throw IOException(GetName(), IO_READ, count);
+ }
+ }
+
+ if (!r) {
+ close();
+ }
+
+ return r;
+}
+
+bool Handle::IsClosed(void) const {
+ return closed;
+}
+
+bool Handle::IsNonBlock(void) const {
+ return nonblock;
+}
+
+void Handle::SetNonBlock(void) {
+#ifdef HAVE_FCNTL
+ if ((h >= 0) || !nonblock) {
+ fcntl(h, F_SETFL, O_NONBLOCK);
+ }
+ nonblock = true;
+#endif
+}
+
+Handle & operator<<(Handle & h, const String & s) {
+ const char * p;
+
+ p = s.to_charp();
+ h.write(p, strlen(p));
+
+ return h;
+}
+
+Handle & operator>>(Handle & h, String & s) {
+ char t[BUFSIZ];
+ int i = 0, r;
+
+ while ((r = h.read(&(t[i]), 1)) && (i != (BUFSIZ - 1))) {
+ // Il y a souvent des \r\n dans les sockets par exemple,
+ // ou bien en lisant des fichiers au format MS-DOS. On
+ // ignore le \r pour ne garder que le \n, standard sous Unix.
+ if (t[i] == '\r') {
+ continue;
+ }
+ if (t[i] == '\n') {
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ t[i] = '\0';
+ s = t;
+ return h;
+}
+
+void Handle::close() throw (GeneralException) {
+ if (IsClosed()) {
+ return;
+ }
+
+ Flush();
+
+ if (h >= 0) {
+ if (z >= 10) {
+ int err;
+ if (c == DEFLATE) {
+ err = deflateEnd(&zstrm);
+ if (err != Z_OK) {
+ throw GeneralException(String(_("Error during deflateEnd: ")) + zstrm.msg);
+ }
+ } else {
+ err = inflateEnd(&zstrm);
+ if (err != Z_OK) {
+ throw GeneralException(String(_("Error during inflateEnd: ")) + zstrm.msg);
+ }
+ }
+ err = ::close(h);
+ if (err) {
+ throw GeneralException(String(_("Error during (zstream) close: ")) + strerror(errno));
+ }
+ } else if (z) {
+#ifdef DEBUG
+ printm(M_INFO, String(_("Performing gzclose on handle ")) + h + "\n");
+#endif
+ int err = gzclose(zfile);
+#ifdef DEBUG
+ printm(M_INFO, String(_("gzclose returned ")) + err + "\n");
+#endif
+ if (err) {
+ if (err == Z_ERRNO) {
+ throw GeneralException(String(_("Error during close: ")) + strerror(errno));
+ } else {
+ throw GeneralException(String(_("Error in zlib during gzclose: ")) + gzerror(zfile, &err));
+ }
+ }
+ } else {
+ if (!hFile) {
+ int err = ::close(h);
+ if (err) {
+ throw GeneralException(String(_("Error during close: ")) + strerror(errno));
+ }
+ }
+ }
+#if defined (_WIN32) && !defined (NO_HFILE)
+ if (hFile) {
+ CloseHandle(hFile);
+ hFile = 0;
+ }
+#endif
+ }
+
+ if (mapped) {
+ munmap();
+ }
+
+ h = -1;
+ closed = 1;
+}
+
+bool Handle::CanRead(void) const {
+ return false;
+}
+
+bool Handle::CanWrite(void) const {
+ return false;
+}
+
+String Handle::GetName(void) const {
+ return _("Bare Handle - should not happend");
+}
+
+ssize_t Handle::GetSize(void) const {
+ return -1;
+}
+
+time_t Handle::GetModif(void) const {
+ return -1;
+}
+
+bool Handle::CanWatch(void) const {
+ return true;
+}
+
+int Handle::Dup() const throw (GeneralException) {
+ int d;
+
+ if ((d = dup(h)) < 0) {
+ throw IOGeneral(String(_("Error dupping file `")) + GetName() + _("' (handle ") + h + "): " + strerror(errno) + " (" + errno + ")");
+ }
+ return d;
+}
+
+void Handle::SetZ(int az) throw (GeneralException) {
+ if (z) {
+ throw GeneralException(_("Can't SetZ a Handle twice."));
+ }
+ if (h < 0) {
+ throw GeneralException(_("Can't SetZ a virtual Handle."));
+ }
+ if (az >= 10) {
+#ifdef DEBUG
+ printm(M_INFO, _("Setting up zstream using inflate/deflate...\n"));
+#endif
+ int err;
+ zstrm.zalloc = Z_NULL;
+ zstrm.zfree = Z_NULL;
+ if (CanWrite()) {
+ c = DEFLATE;
+ err = deflateInit(&zstrm, az - 10);
+ if (err != Z_OK) {
+ throw GeneralException(String(_("Error in deflateInit: ")) + zstrm.msg);
+ }
+ } else {
+ c = INFLATE;
+ zstrm.next_in = 0;
+ zstrm.avail_in = 0;
+ err = inflateInit(&zstrm);
+ if (err != Z_OK) {
+ throw GeneralException(String(_("Error in inflateInit: ")) + zstrm.msg);
+ }
+ }
+ } else if (az) {
+ char format[5];
+ int index = 0;
+ if (CanRead()) {
+ format[index++] = 'r';
+ }
+ if (CanWrite()) {
+ format[index++] = 'w';
+ }
+ format[index++] = (char) (az + '0');
+ format[index++] = 'b';
+ format[index] = 0;
+#ifdef FULLDEBUG
+ printm(M_INFO, String(_("Performing gzdopen on handle ")) + h + _(" with mode \"") + format + "\"\n");
+#endif
+ if (!(zfile = gzdopen(h, format))) {
+ throw GeneralException(String(_("Was not able to gzdopen: ")) + strerror(errno));
+ }
+ z = az;
+ }
+}
+
+ssize_t Handle::uwrite(const void * buf, size_t count) throw (GeneralException) {
+ if (z >= 10) {
+ } else if (z) {
+#ifdef FULLDEBUG
+ printm(M_INFO, String(_("Performing gzwrite of ")) + count + _(" byte(s) for handle ") + h + "\n");
+#endif
+#ifdef HAVE_WD_ZLIB
+ int err = gzwrite(zfile, buf, count);
+#else
+ int err = gzwrite(zfile, (char *) buf, count);
+#endif
+ if (err == 0) {
+ const char * m = gzerror(zfile, &err);
+ if (err == Z_ERRNO) {
+ return -1;
+ } else {
+ throw GeneralException(String(_("Error in zlib during gzwrite: ")) + m);
+ }
+ }
+ itell += err;
+ return err;
+ } else {
+ itell += count = ::write(h, buf, count);
+ return count;
+ }
+}
+
+ssize_t Handle::uread(void * buf, size_t count) {
+ if (z >= 10) {
+ } if (z) {
+#ifdef DEBUG
+ printm(M_BARE, String(_("Performing gzread of ")) + count + _(" byte(s) for handle ") + h + "\n");
+#endif
+ int err = gzread(zfile, buf, count);
+ if (err == -1) {
+ gzerror(zfile, &err);
+ if (err == Z_ERRNO) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ itell += err;
+ return err;
+ } else {
+#if defined (_WIN32) && !defined (NO_HFILE)
+ if (hFile) {
+ DWORD rcount;
+ if (!ReadFile(hFile, buf, count, &rcount, 0)) {
+ // Error..
+ }
+ itell += count = rcount;
+ } else
+#endif
+ itell += count = ::read(h, buf, count);
+ return count;
+ }
+}
+
+off_t Handle::tell() const {
+ if (z) {
+ return gztell(zfile);
+ } else {
+ return itell;
+ }
+}
+
+bool Handle::CanSeek() const {
+ return 0;
+}
+
+off_t Handle::seek(off_t offset, int whence) throw(GeneralException) {
+ if (z) {
+ return itell = gzseek(zfile, offset, whence);
+ } else {
+ throw IOGeneral(_("Handle ") + GetName() + _(" can't seek"));
+ }
+}
+
+Uint8 Handle::readU8() {
+ Uint8 r;
+ read(&r, 1);
+ return r;
+}
+
+Uint16 Handle::readU16() {
+ Uint16 r;
+ read(&r, 2);
+#ifdef WORDS_BIGENDIAN
+ return bswap_16(r);
+#else
+ return r;
+#endif
+}
+
+Uint32 Handle::readU32() {
+ Uint32 r;
+ read(&r, 4);
+#ifdef WORDS_BIGENDIAN
+ return bswap_32(r);
+#else
+ return r;
+#endif
+}
+
+void Handle::writeU8(Uint8 v) {
+ write(&v, 1);
+}
+
+void Handle::writeU16(Uint16 v) {
+#ifdef WORDS_BIGENDIAN
+ Uint16 t = bswap_16(v);
+ write(&t, 2);
+#else
+ write(&v, 2);
+#endif
+}
+
+void Handle::writeU32(Uint32 v) {
+#ifdef WORDS_BIGENDIAN
+ Uint32 t = bswap_32(v);
+ write(&t, 4);
+#else
+ write(&v, 4);
+#endif
+}
+
+void Handle::copyto(Handle * dest, ssize_t s) {
+ copy(this, dest, s);
+}
+
+void Handle::copyfrom(Handle * src, ssize_t s) {
+ copy(src, this, s);
+}
+
+void copyone(Handle * s, Handle * d, ssize_t size) {
+ long i;
+ unsigned char c;
+ long r;
+
+ if (size < 0)
+ size = s->GetSize();
+
+ for (i = 0; (i < size) || (size < 0); i++) {
+ r = s->read(&c, 1);
+ if (r == 0) {
+ break;
+ }
+ d->write(&c, 1);
+ }
+}
+
+#define BSIZE 20480
+
+void copy(Handle * s, Handle * d, ssize_t size) {
+ long i;
+ static unsigned char b[BSIZE];
+ long r;
+
+ if (size < 0)
+ size = s->GetSize();
+
+ LOCK;
+
+ while (size) {
+ if ((size > BSIZE) || (size < 0)) {
+ r = s->read(b, BSIZE);
+ if (r)
+ d->write(b, r);
+ } else {
+ r = s->read(b, size);
+ if (r)
+ d->write(b, r);
+ }
+ if (!r)
+ break;
+ if (size > 0)
+ size -= r;
+ }
+
+ UNLOCK;
+}
+
+void Handle::Flush() {
+ if (!CanWrite())
+ return;
+ if (h < 0)
+ return;
+ if (z >= 10) {
+
+ } else if (z) {
+ gzflush(&z, Z_FULL_FLUSH);
+ } else {
+#ifdef HAVE_FSYNC
+ fsync(h);
+#endif
+ }
+}
+
+void * Handle::mmap(off_t offset, size_t length) throw (GeneralException) {
+ void * r;
+
+ if (h == -1) {
+ throw GeneralException("Can't mmap() a virtual handle");
+ }
+#ifdef _WIN32
+ if (!hFile) {
+ throw GeneralException("Can't mmap() a non-hFile handle under windows");
+ }
+#endif
+ if (mapped) {
+ throw GeneralException("Handle already mmap()ped");
+ }
+ mapped = true;
+ if (length == -1) {
+ length = GetSize();
+ }
+ maplength = length;
+#ifndef _WIN32
+ r = ::mmap(0, length, (CanRead() ? PROT_READ : 0) | (CanWrite() ? PROT_WRITE : 0), MAP_SHARED, h, offset);
+ if (!r) {
+ throw GeneralException(String("Was not able to mmap(): ") + strerror(errno));
+ }
+#else
+ hMapObject = CreateFileMapping(
+ hFile,
+ 0,
+ CanWrite() ? PAGE_READWRITE : PAGE_READONLY,
+ 0,
+ length,
+ GetName().to_charp());
+ if (hMapObject != NULL) {
+ r = MapViewOfFile(
+ hMapObject,
+ CanWrite() ? FILE_MAP_WRITE : FILE_MAP_READ,
+ 0,
+ offset,
+ length);
+ if (!r) {
+ CloseHandle(hMapObject);
+ throw GeneralException("Was not able to MapViewOfFile()");
+ }
+ } else {
+ throw GeneralException("Was not able to CreateFileMapping()");
+ }
+#endif
+
+ mappedarea = r;
+
+ return r;
+}
+
+void Handle::munmap() throw (GeneralException) {
+ if (!mapped) {
+ throw GeneralException("Can't munmap, was not mapped");
+ }
+#ifndef _WIN32
+ if (::munmap(mappedarea, maplength)) {
+ throw GeneralException(String("Was not able to munmap(): ") + strerror(errno));
+ }
+#else
+ if (!UnmapViewOfFile(mappedarea)) {
+ throw GeneralException("Was not able to UnmapViewOfFile()");
+ }
+ CloseHandle(hMapObject);
+#endif
+ mapped = false;
+ mappedarea = 0;
+ maplength = 0;
+}
diff --git a/lib/HttpServ.cc b/lib/HttpServ.cc index a4101a7..a8e7301 100644 --- a/lib/HttpServ.cc +++ b/lib/HttpServ.cc @@ -1,473 +1,473 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Socket.h" -#include "Action.h" -#include "HttpServ.h" -#include "Buffer.h" -#include "ReadJob.h" -#include "CopyJob.h" -#include "Task.h" -#include "gettext.h" - -String endhl = "\r\n", endnl = "\n"; - -class ProcessRequest : public Task { - public: - ProcessRequest(Action *, const Socket &, const String &, int); - virtual ~ProcessRequest() {} - virtual String GetName(); - protected: - virtual int Do() throw (GeneralException); - private: - String GetMime(const String &); - bool ParseUri(String &, String &, String &, Handle *); - void ParseVars(Handle *, int); - void ShowError(Handle *); - void SendHeads(Handle *, const String &, const String & = "", time_t = -1); - void SendRedirect(Handle *); - - String file, domain, t; - Buffer b; - Task * c, * a; - Action * f; - int len, localport; - Action * p; - Socket s; - - String name, host, gvars; - Variables * Vars, * Heads; - bool bad, hasvars, post; -}; - -ProcessRequest::ProcessRequest(Action * ap, const Socket & as, const String & aname, int aport) : localport(aport), p(ap), s(as), name(aname) { - SetBurst(); -} - -String ProcessRequest::GetName() { - return _("Processing HTTP request"); -} - -int ProcessRequest::Do() throw(GeneralException) { - switch (current) { - case 0: - if (!s.IsConnected()) return TASK_DONE; - - c = new ReadJob(&s, &b); - WaitFor(c); - current = 1; - Suspend(TASK_ON_HOLD); - - case 1: - delete c; - - bad = false; - -// std::cerr << "---- Got a request from handle " << s.GetHandle() << " \n"; - - post = ParseUri(file, domain, gvars, &b); - - Heads = new Variables(); - Vars = new Variables(); - - len = -1; - do { - int p; - b >> t; -// std::cerr << "Read Request (n): " << t << std::endl; - if ((t.strstr("Content-Length: ") == 0) || (t.strstr("Content-length: ") == 0)) { -// std::cerr << "Saw 'Content-Lenght:', reading length from '" << t.extract(16) << "'\n"; - len = t.extract(16).to_int(); - } - if (t.strstr("Host: ") == 0) { - host = t.extract(6); - } - - if ((p = t.strchr(':')) >= 0) { - String s = t.extract(0, p - 1); - s += '='; - s += t.extract(p + 2); - Heads->Add(s); - } - } while (t.strlen()); - -// std::cerr << "---- Processing it.\n"; - - hasvars = false; - - if (post) { - // On a pas eu de ligne 'Content-Length' mais on a eu une méthode POST. - // Cela est une erreur. - if (len == -1) { -// std::cerr << "Error: method POST but no Content-Length\n"; - bad = true; - } else { -// std::cerr << "Got a POST request. Parsing variables. (len = " << len << ")\n"; - // Les variables seront initialisées ici. - hasvars = true; - } - } - - current = 2; - if (hasvars && (len)) { - c = new CopyJob(&s, &b, len); - WaitFor(c); - Suspend(); - } else { - c = 0; - } - - case 2: - if (gvars != "") { - Buffer b2; - b2 << gvars; - ParseVars(&b2, gvars.strlen()); - } - if (hasvars) { - if (c) delete c; - ParseVars(&b, len); - } - - std::cerr << " Domain = '" << domain << "' - File = '" << file << "'\n"; - - if (!bad) { - // Nous vérifions le domaine. - if (domain != "") { - bad = true; - // Les domaines valides sont '/', '/bin' et '/image'. - if (domain == "/image") bad = false; - if (domain == "/bin") bad = false; - if (domain == "/") bad = false; - if (bad) { - std::cerr << _("Error: bad domain.\n"); - } - } else { - // L'url sans domaine ni fichier est valide. (cela arrive sur certains navigateurs...) - bad = (file != ""); - } - } - - a = 0; - - if (bad) { - ShowError(&b); - } else { - if (((domain == "") || (domain == "/")) && (file == "")) { - // Si le navigateur a demandé l'URL '/', alors on renvoie une notification - // de redirection. - SendRedirect(&b); - } else if (domain == "/bin") { - // Le domaine 'bin' est réservé aux actions. On cherche donc l'action à effectuer. - if ((f = p->Look4URL(file))) { - SendHeads(&b, "text/html"); - a = f->Do(Vars, Heads, &s); - } else { - ShowError(&b); - } - } else { - // Dans tous les autres cas de domaine, on cherche le fichier dans le répertoire datas. - // On utilise try au cas où le fichier n'existe pas et donc que le constructeur - // d'input renvoie une erreur. - try { - Handle * i = new Input(String("datas/") + file); - SendHeads(&b, GetMime(file), String("Accept-Ranges: bytes") + endhl + "Content-Length: " + (unsigned long long int) i->GetSize() + endhl, i->GetModif()); - i->SetNonBlock(); - a = new CopyJob(i, &s); - std::cerr << _("File found, dumping.\n"); - } - catch (IOGeneral e) { - ShowError(&b); - std::cerr << _("File not found, error showed.\n"); - } - } - } - - if (a) a->Stop(); - - delete Vars; - delete Heads; -// std::cerr << "---- Sending header buffer.\n"; - c = new CopyJob(&b, &s, -1, false); - WaitFor(c); - current = 3; - Suspend(); - - case 3: - delete c; - - if (a) { -// std::cerr << "---- Sending contents.\n"; - a->Restart(); - WaitFor(a); - current = 4; - Suspend(); - } - - case 4: - if (a) delete a; -// std::cerr << "---- End of Request.\n"; - } - return TASK_DONE; -} - -void ProcessRequest::ParseVars(Handle * s, int len) { - String t, v; - char conv[3], l; - int hconv, nbvars; - ssize_t pos = 0, next; - - t = ""; - for (int i = 0; i < len; i++) { - s->read(&l, 1); - t += l; - } -// std::cerr << "Post variables line: '" << t << "'\n"; - - - // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc le nombre d'occurences - // du caractère '=' indique le nombre de variables. - nbvars = t.strchrcnt('='); - - for (int i = 0; i < nbvars; i++) { - // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc on cherche le caractère - // & dans la chaine POST. - next = t.strchr('&', pos); - if (next < 0) next = t.strlen(); - v = ""; - while (pos != next) { - switch (t[pos]) { - // Le navigateur encode les caractères spéciaux à l'aide du format %XX où XX indique - // la valeur hexadécimale du caractère. Nous encodons surtout les caractères - // ' ', '=', '%', et '/' avec cette technique. - case '%': - pos++; - conv[0] = t[pos++]; - conv[1] = t[pos++]; - conv[2] = '\0'; - sscanf(conv, "%x", &hconv); - v += ((char) hconv); - break; - // Certains navigateurs utilisent '+' pour indiquer ' ' (qui est illégal) au lieu - // d'utiliser %20. - case '+': - v += ' '; - pos++; - break; - default: - v += t[pos++]; - } - } -// std::cerr << "Pushing HTTP variable: " << v << std::endl; - Vars->Add(v); - pos++; - } -} - -/* - * Cette fonction renverra true si la méthode est une méthode POST. - * Les Strings domain et file seront modifiées afin de renvoyer le domaine - * et le fichier lut. La string s doit donner la première ligne de la requète, - * c'est à dire la méthode demandée par le client. - */ - -bool ProcessRequest::ParseUri(String & file, String & domain, String & gvars, Handle * s) { - String t, Uri; - bool post = false; - const char * p = 0; - ssize_t sppos; - - *s >> t; - std::cerr << _("Read Request (1): ") << t << std::endl; - - int IPos = t.strchr('?'); - - gvars = ""; - - if (IPos >= 0) { - int HPos = t.strchr(' ', IPos); - char * sdup = t.strdup(0, IPos - 1); - gvars = t.extract(IPos + 1, HPos - 1); - t = sdup; - free(sdup); - } - -// std::cerr << "New request: " << t << ", gvars = " << gvars << std::endl; - - bad = false; - - // p nous indiquera la position de la chaîne URL. - switch (t[0]) { - case 'P': /* POST? */ - if (t.extract(1, 4) == "OST ") { - p = t.to_charp(5); - post = true; - } else { -// std::cerr << "Error: unknow request.\n"; - bad = true; - } - break; - case 'G': /* GET? */ - if (t.extract(1, 3) == "ET ") { - p = t.to_charp(4); - } else { -// std::cerr << "Error: unknow request.\n"; - bad = true; - } - break; - default: -// std::cerr << "Error: unknow request.\n"; - bad = true; - } - - if (!bad) { - ssize_t poshttp, posslash; - Uri = p; - sppos = Uri.strrchr(' '); - p = Uri.to_charp(0, sppos - 1); - Uri = p; - // On enlève tout le host spécifié éventuellement dans la requete. - if ((poshttp = Uri.strstr("http://")) > 0) { - Uri = Uri.to_charp(poshttp + 7); - posslash = Uri.strchr('/'); - // Certains navigateurs indiqueront uniquement http://host comme URL. - if (posslash >= 0) { - host = Uri.extract(0, posslash - 1); - Uri = Uri.to_charp(posslash); - } else { - host = Uri; - Uri = ""; - } - } - posslash = Uri.strrchr('/'); - file = Uri.to_charp(posslash + 1); - if (posslash > 0) { - domain = Uri.to_charp(0, posslash - 1); - } else { - domain = ""; - } - } - return post; -} - -/* - * Ceci sert à rediriger le navigateur vers l'url de démarrage. - */ -void ProcessRequest::SendRedirect(Handle * s) { - *s << "HTTP/1.1 301 Moved Permanently" << endhl << - "Server: " << name << endhl << - "Location: http://" << host << "/bin/start" << endhl << - "Cache-Control: no-cache" << endhl << - "Connection: closed" << endhl << - "Content-Type: text/html" << endhl << endhl << - "<HTML><HEAD><TITLE>301 - Moved Permanently</TITLE></HEAD>" << endnl << - "<BODY><center><b><h2>You should be redirected to the " << endnl << endnl << - "<a href=\"http://" << host << "/bin/start\">start page</a></h2></b></center>" << endnl << - "</BODY></HTML>" << endnl; -} - -/* - * Nous envoyons les entetes de réponse HTTP. - */ - -void ProcessRequest::SendHeads(Handle * s, const String & mime, const String & extra, time_t lm) { - time_t t = time(NULL); - struct tm * ft = gmtime(&t); - char buf[1024]; - strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft); - *s << "HTTP/1.1 200 OK" << endhl << - "Date: " << buf << endhl << - "Server: " << name << endhl; - if (lm >=0) { - ft = gmtime(&lm); - strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft); - } - *s << "Last-Modified: " << buf << endhl << extra << - "Connection: closed" << endhl << - "Content-Type: " << mime << endhl << endhl; -} - -/* - * Affichage d'une erreur 404. - */ - -void ProcessRequest::ShowError(Handle * s) { - *s << "HTTP/1.1 404 Not Found" << endhl << - "Server: " << name << endhl << - "Cache-Control: no-cache" << endhl << - "Connection: closed" << endhl << - "Content-Type: text/html" << endhl << endhl << - "<HTML><HEAD><TITLE>404 - Error</TITLE></HEAD>" << endnl << - "<BODY><center><b><h2>The server was unable to process your query</h2></b></center>" << endnl << - "Click <A HREF=\"/\">here</A> to go the main page." << - "</BODY></HTML>" << endnl; -} - -/* - * Sert à déterminer le type mime à partir de l'extension du fichier. - * Par défaut, nous mettons "text/plain". - */ - -String ProcessRequest::GetMime(const String & f) { - String ext; - size_t ppos; - - ppos = f.strrchr('.'); - - if (ppos >= 0) { - ext = f.extract(ppos + 1); - if (ext == "jpg") return "image/jpeg"; - if (ext == "jpeg") return "image/jpeg"; - if (ext == "htm") return "text/html"; - if (ext == "html") return "text/html"; - if (ext == "gif") return "image/gif"; - if (ext == "png") return "image/png"; - if (ext == "class") return "application/octet-stream"; - } - - return "text/plain"; -} - -HttpServ::HttpServ(Action * ap, int port, const String & nname) throw (GeneralException) { - bool r = true; - - p = ap; - name = nname; - localport = port; - -// std::cerr << "Initialising Mini HTTP-Server on port " << localport << std::endl; - - r = Listener.SetLocal("", port); - if (!r) { - throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't bind")); - } - - r = Listener.Listen(); - - if (!r) { - throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't listen")); - } - - Listener.SetNonBlock(); - WaitFor(&Listener, W4_STICKY | W4_READING); - -// std::cerr << "Mini HTTP-Server '" << name << "' ready and listening for port " << port << std::endl; -} - -HttpServ::~HttpServ(void) { - Listener.close(); -} - -int HttpServ::Do() throw (GeneralException) { - try { - Socket s = Listener.Accept(); - s.SetNonBlock(); - new ProcessRequest(p, s, name, localport); - } - catch (GeneralException) { - } - return TASK_ON_HOLD; -} - -String HttpServ::GetName() { - return String("Mini HTTP-Server '") + name + "'"; -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Socket.h"
+#include "Action.h"
+#include "HttpServ.h"
+#include "Buffer.h"
+#include "ReadJob.h"
+#include "CopyJob.h"
+#include "Task.h"
+#include "gettext.h"
+
+String endhl = "\r\n", endnl = "\n";
+
+class ProcessRequest : public Task {
+ public:
+ ProcessRequest(Action *, const Socket &, const String &, int);
+ virtual ~ProcessRequest() {}
+ virtual String GetName();
+ protected:
+ virtual int Do() throw (GeneralException);
+ private:
+ String GetMime(const String &);
+ bool ParseUri(String &, String &, String &, Handle *);
+ void ParseVars(Handle *, int);
+ void ShowError(Handle *);
+ void SendHeads(Handle *, const String &, const String & = "", time_t = -1);
+ void SendRedirect(Handle *);
+
+ String file, domain, t;
+ Buffer b;
+ Task * c, * a;
+ Action * f;
+ int len, localport;
+ Action * p;
+ Socket s;
+
+ String name, host, gvars;
+ Variables * Vars, * Heads;
+ bool bad, hasvars, post;
+};
+
+ProcessRequest::ProcessRequest(Action * ap, const Socket & as, const String & aname, int aport) : localport(aport), p(ap), s(as), name(aname) {
+ SetBurst();
+}
+
+String ProcessRequest::GetName() {
+ return _("Processing HTTP request");
+}
+
+int ProcessRequest::Do() throw(GeneralException) {
+ switch (current) {
+ case 0:
+ if (!s.IsConnected()) return TASK_DONE;
+
+ c = new ReadJob(&s, &b);
+ WaitFor(c);
+ current = 1;
+ Suspend(TASK_ON_HOLD);
+
+ case 1:
+ delete c;
+
+ bad = false;
+
+// std::cerr << "---- Got a request from handle " << s.GetHandle() << " \n";
+
+ post = ParseUri(file, domain, gvars, &b);
+
+ Heads = new Variables();
+ Vars = new Variables();
+
+ len = -1;
+ do {
+ int p;
+ b >> t;
+// std::cerr << "Read Request (n): " << t << std::endl;
+ if ((t.strstr("Content-Length: ") == 0) || (t.strstr("Content-length: ") == 0)) {
+// std::cerr << "Saw 'Content-Lenght:', reading length from '" << t.extract(16) << "'\n";
+ len = t.extract(16).to_int();
+ }
+ if (t.strstr("Host: ") == 0) {
+ host = t.extract(6);
+ }
+
+ if ((p = t.strchr(':')) >= 0) {
+ String s = t.extract(0, p - 1);
+ s += '=';
+ s += t.extract(p + 2);
+ Heads->Add(s);
+ }
+ } while (t.strlen());
+
+// std::cerr << "---- Processing it.\n";
+
+ hasvars = false;
+
+ if (post) {
+ // On a pas eu de ligne 'Content-Length' mais on a eu une méthode POST.
+ // Cela est une erreur.
+ if (len == -1) {
+// std::cerr << "Error: method POST but no Content-Length\n";
+ bad = true;
+ } else {
+// std::cerr << "Got a POST request. Parsing variables. (len = " << len << ")\n";
+ // Les variables seront initialisées ici.
+ hasvars = true;
+ }
+ }
+
+ current = 2;
+ if (hasvars && (len)) {
+ c = new CopyJob(&s, &b, len);
+ WaitFor(c);
+ Suspend();
+ } else {
+ c = 0;
+ }
+
+ case 2:
+ if (gvars != "") {
+ Buffer b2;
+ b2 << gvars;
+ ParseVars(&b2, gvars.strlen());
+ }
+ if (hasvars) {
+ if (c) delete c;
+ ParseVars(&b, len);
+ }
+
+ std::cerr << " Domain = '" << domain << "' - File = '" << file << "'\n";
+
+ if (!bad) {
+ // Nous vérifions le domaine.
+ if (domain != "") {
+ bad = true;
+ // Les domaines valides sont '/', '/bin' et '/image'.
+ if (domain == "/image") bad = false;
+ if (domain == "/bin") bad = false;
+ if (domain == "/") bad = false;
+ if (bad) {
+ std::cerr << _("Error: bad domain.\n");
+ }
+ } else {
+ // L'url sans domaine ni fichier est valide. (cela arrive sur certains navigateurs...)
+ bad = (file != "");
+ }
+ }
+
+ a = 0;
+
+ if (bad) {
+ ShowError(&b);
+ } else {
+ if (((domain == "") || (domain == "/")) && (file == "")) {
+ // Si le navigateur a demandé l'URL '/', alors on renvoie une notification
+ // de redirection.
+ SendRedirect(&b);
+ } else if (domain == "/bin") {
+ // Le domaine 'bin' est réservé aux actions. On cherche donc l'action à effectuer.
+ if ((f = p->Look4URL(file))) {
+ SendHeads(&b, "text/html");
+ a = f->Do(Vars, Heads, &s);
+ } else {
+ ShowError(&b);
+ }
+ } else {
+ // Dans tous les autres cas de domaine, on cherche le fichier dans le répertoire datas.
+ // On utilise try au cas où le fichier n'existe pas et donc que le constructeur
+ // d'input renvoie une erreur.
+ try {
+ Handle * i = new Input(String("datas/") + file);
+ SendHeads(&b, GetMime(file), String("Accept-Ranges: bytes") + endhl + "Content-Length: " + (unsigned long long int) i->GetSize() + endhl, i->GetModif());
+ i->SetNonBlock();
+ a = new CopyJob(i, &s);
+ std::cerr << _("File found, dumping.\n");
+ }
+ catch (IOGeneral e) {
+ ShowError(&b);
+ std::cerr << _("File not found, error showed.\n");
+ }
+ }
+ }
+
+ if (a) a->Stop();
+
+ delete Vars;
+ delete Heads;
+// std::cerr << "---- Sending header buffer.\n";
+ c = new CopyJob(&b, &s, -1, false);
+ WaitFor(c);
+ current = 3;
+ Suspend();
+
+ case 3:
+ delete c;
+
+ if (a) {
+// std::cerr << "---- Sending contents.\n";
+ a->Restart();
+ WaitFor(a);
+ current = 4;
+ Suspend();
+ }
+
+ case 4:
+ if (a) delete a;
+// std::cerr << "---- End of Request.\n";
+ }
+ return TASK_DONE;
+}
+
+void ProcessRequest::ParseVars(Handle * s, int len) {
+ String t, v;
+ char conv[3], l;
+ int hconv, nbvars;
+ ssize_t pos = 0, next;
+
+ t = "";
+ for (int i = 0; i < len; i++) {
+ s->read(&l, 1);
+ t += l;
+ }
+// std::cerr << "Post variables line: '" << t << "'\n";
+
+
+ // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc le nombre d'occurences
+ // du caractère '=' indique le nombre de variables.
+ nbvars = t.strchrcnt('=');
+
+ for (int i = 0; i < nbvars; i++) {
+ // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc on cherche le caractère
+ // & dans la chaine POST.
+ next = t.strchr('&', pos);
+ if (next < 0) next = t.strlen();
+ v = "";
+ while (pos != next) {
+ switch (t[pos]) {
+ // Le navigateur encode les caractères spéciaux à l'aide du format %XX où XX indique
+ // la valeur hexadécimale du caractère. Nous encodons surtout les caractères
+ // ' ', '=', '%', et '/' avec cette technique.
+ case '%':
+ pos++;
+ conv[0] = t[pos++];
+ conv[1] = t[pos++];
+ conv[2] = '\0';
+ sscanf(conv, "%x", &hconv);
+ v += ((char) hconv);
+ break;
+ // Certains navigateurs utilisent '+' pour indiquer ' ' (qui est illégal) au lieu
+ // d'utiliser %20.
+ case '+':
+ v += ' ';
+ pos++;
+ break;
+ default:
+ v += t[pos++];
+ }
+ }
+// std::cerr << "Pushing HTTP variable: " << v << std::endl;
+ Vars->Add(v);
+ pos++;
+ }
+}
+
+/*
+ * Cette fonction renverra true si la méthode est une méthode POST.
+ * Les Strings domain et file seront modifiées afin de renvoyer le domaine
+ * et le fichier lut. La string s doit donner la première ligne de la requète,
+ * c'est à dire la méthode demandée par le client.
+ */
+
+bool ProcessRequest::ParseUri(String & file, String & domain, String & gvars, Handle * s) {
+ String t, Uri;
+ bool post = false;
+ const char * p = 0;
+ ssize_t sppos;
+
+ *s >> t;
+ std::cerr << _("Read Request (1): ") << t << std::endl;
+
+ int IPos = t.strchr('?');
+
+ gvars = "";
+
+ if (IPos >= 0) {
+ int HPos = t.strchr(' ', IPos);
+ char * sdup = t.strdup(0, IPos - 1);
+ gvars = t.extract(IPos + 1, HPos - 1);
+ t = sdup;
+ free(sdup);
+ }
+
+// std::cerr << "New request: " << t << ", gvars = " << gvars << std::endl;
+
+ bad = false;
+
+ // p nous indiquera la position de la chaîne URL.
+ switch (t[0]) {
+ case 'P': /* POST? */
+ if (t.extract(1, 4) == "OST ") {
+ p = t.to_charp(5);
+ post = true;
+ } else {
+// std::cerr << "Error: unknow request.\n";
+ bad = true;
+ }
+ break;
+ case 'G': /* GET? */
+ if (t.extract(1, 3) == "ET ") {
+ p = t.to_charp(4);
+ } else {
+// std::cerr << "Error: unknow request.\n";
+ bad = true;
+ }
+ break;
+ default:
+// std::cerr << "Error: unknow request.\n";
+ bad = true;
+ }
+
+ if (!bad) {
+ ssize_t poshttp, posslash;
+ Uri = p;
+ sppos = Uri.strrchr(' ');
+ p = Uri.to_charp(0, sppos - 1);
+ Uri = p;
+ // On enlève tout le host spécifié éventuellement dans la requete.
+ if ((poshttp = Uri.strstr("http://")) > 0) {
+ Uri = Uri.to_charp(poshttp + 7);
+ posslash = Uri.strchr('/');
+ // Certains navigateurs indiqueront uniquement http://host comme URL.
+ if (posslash >= 0) {
+ host = Uri.extract(0, posslash - 1);
+ Uri = Uri.to_charp(posslash);
+ } else {
+ host = Uri;
+ Uri = "";
+ }
+ }
+ posslash = Uri.strrchr('/');
+ file = Uri.to_charp(posslash + 1);
+ if (posslash > 0) {
+ domain = Uri.to_charp(0, posslash - 1);
+ } else {
+ domain = "";
+ }
+ }
+ return post;
+}
+
+/*
+ * Ceci sert à rediriger le navigateur vers l'url de démarrage.
+ */
+void ProcessRequest::SendRedirect(Handle * s) {
+ *s << "HTTP/1.1 301 Moved Permanently" << endhl <<
+ "Server: " << name << endhl <<
+ "Location: http://" << host << "/bin/start" << endhl <<
+ "Cache-Control: no-cache" << endhl <<
+ "Connection: closed" << endhl <<
+ "Content-Type: text/html" << endhl << endhl <<
+ "<HTML><HEAD><TITLE>301 - Moved Permanently</TITLE></HEAD>" << endnl <<
+ "<BODY><center><b><h2>You should be redirected to the " << endnl << endnl <<
+ "<a href=\"http://" << host << "/bin/start\">start page</a></h2></b></center>" << endnl <<
+ "</BODY></HTML>" << endnl;
+}
+
+/*
+ * Nous envoyons les entetes de réponse HTTP.
+ */
+
+void ProcessRequest::SendHeads(Handle * s, const String & mime, const String & extra, time_t lm) {
+ time_t t = time(NULL);
+ struct tm * ft = gmtime(&t);
+ char buf[1024];
+ strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft);
+ *s << "HTTP/1.1 200 OK" << endhl <<
+ "Date: " << buf << endhl <<
+ "Server: " << name << endhl;
+ if (lm >=0) {
+ ft = gmtime(&lm);
+ strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft);
+ }
+ *s << "Last-Modified: " << buf << endhl << extra <<
+ "Connection: closed" << endhl <<
+ "Content-Type: " << mime << endhl << endhl;
+}
+
+/*
+ * Affichage d'une erreur 404.
+ */
+
+void ProcessRequest::ShowError(Handle * s) {
+ *s << "HTTP/1.1 404 Not Found" << endhl <<
+ "Server: " << name << endhl <<
+ "Cache-Control: no-cache" << endhl <<
+ "Connection: closed" << endhl <<
+ "Content-Type: text/html" << endhl << endhl <<
+ "<HTML><HEAD><TITLE>404 - Error</TITLE></HEAD>" << endnl <<
+ "<BODY><center><b><h2>The server was unable to process your query</h2></b></center>" << endnl <<
+ "Click <A HREF=\"/\">here</A> to go the main page." <<
+ "</BODY></HTML>" << endnl;
+}
+
+/*
+ * Sert à déterminer le type mime à partir de l'extension du fichier.
+ * Par défaut, nous mettons "text/plain".
+ */
+
+String ProcessRequest::GetMime(const String & f) {
+ String ext;
+ size_t ppos;
+
+ ppos = f.strrchr('.');
+
+ if (ppos >= 0) {
+ ext = f.extract(ppos + 1);
+ if (ext == "jpg") return "image/jpeg";
+ if (ext == "jpeg") return "image/jpeg";
+ if (ext == "htm") return "text/html";
+ if (ext == "html") return "text/html";
+ if (ext == "gif") return "image/gif";
+ if (ext == "png") return "image/png";
+ if (ext == "class") return "application/octet-stream";
+ }
+
+ return "text/plain";
+}
+
+HttpServ::HttpServ(Action * ap, int port, const String & nname) throw (GeneralException) {
+ bool r = true;
+
+ p = ap;
+ name = nname;
+ localport = port;
+
+// std::cerr << "Initialising Mini HTTP-Server on port " << localport << std::endl;
+
+ r = Listener.SetLocal("", port);
+ if (!r) {
+ throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't bind"));
+ }
+
+ r = Listener.Listen();
+
+ if (!r) {
+ throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't listen"));
+ }
+
+ Listener.SetNonBlock();
+ WaitFor(&Listener, W4_STICKY | W4_READING);
+
+// std::cerr << "Mini HTTP-Server '" << name << "' ready and listening for port " << port << std::endl;
+}
+
+HttpServ::~HttpServ(void) {
+ Listener.close();
+}
+
+int HttpServ::Do() throw (GeneralException) {
+ try {
+ Socket s = Listener.Accept();
+ s.SetNonBlock();
+ new ProcessRequest(p, s, name, localport);
+ }
+ catch (GeneralException) {
+ }
+ return TASK_ON_HOLD;
+}
+
+String HttpServ::GetName() {
+ return String("Mini HTTP-Server '") + name + "'";
+}
@@ -1,234 +1,234 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "BString.h" -#include "IRC.h" -#include "HttpServ.h" - -ircmsg_t ircmsgs[MSG_COUNT] = - -{ - { "RPL_WELCOME", RPL_WELCOME }, - { "RPL_YOURHOST", RPL_YOURHOST }, - { "RPL_CREATED", RPL_CREATED }, - { "RPL_MYINFO", RPL_MYINFO }, - { "RPL_BOUNCE", RPL_BOUNCE }, - { "RPL_TRACELINK", RPL_TRACELINK }, - { "RPL_TRACECONNECTING", RPL_TRACECONNECTING }, - { "RPL_TRACEHANDSHAKE", RPL_TRACEHANDSHAKE }, - { "RPL_TRACEUNKNOWN", RPL_TRACEUNKNOWN }, - { "RPL_TRACEOPERATOR", RPL_TRACEOPERATOR }, - { "RPL_TRACEUSER", RPL_TRACEUSER }, - { "RPL_TRACESERVER", RPL_TRACESERVER }, - { "RPL_TRACESERVICE", RPL_TRACESERVICE }, - { "RPL_TRACENEWTYPE", RPL_TRACENEWTYPE }, - { "RPL_TRACECLASS", RPL_TRACECLASS }, - { "RPL_TRACERECONNECT", RPL_TRACERECONNECT }, - { "RPL_STATSLINKINFO", RPL_STATSLINKINFO }, - { "RPL_STATSCOMMANDS", RPL_STATSCOMMANDS }, - { "RPL_STATSCLINE", RPL_STATSCLINE }, - { "RPL_STATSILINE", RPL_STATSILINE }, - { "RPL_STATSQLINE", RPL_STATSQLINE }, - { "RPL_ENDOFSTATS", RPL_ENDOFSTATS }, - { "RPL_UMODEIS", RPL_UMODEIS }, - { "RPL_SERVICEINFO", RPL_SERVICEINFO }, - { "RPL_SERVICE", RPL_SERVICE }, - { "RPL_SERVLIST", RPL_SERVLIST }, - { "RPL_SERVLISTEND", RPL_SERVLISTEND }, - { "RPL_STATSVLINE", RPL_STATSVLINE }, - { "RPL_STATSUPTIME", RPL_STATSUPTIME }, - { "RPL_STATSOLINE", RPL_STATSOLINE }, - { "RPL_STATSHLINE", RPL_STATSHLINE }, - { "RPL_STATSPING", RPL_STATSPING }, - { "RPL_STATSDLINE", RPL_STATSDLINE }, - { "RPL_LUSERCLIENT", RPL_LUSERCLIENT }, - { "RPL_LUSEROP", RPL_LUSEROP }, - { "RPL_LUSERUNKNOWN", RPL_LUSERUNKNOWN }, - { "RPL_LUSERCHANNELS", RPL_LUSERCHANNELS }, - { "RPL_LUSERME", RPL_LUSERME }, - { "RPL_ADMINME", RPL_ADMINME }, - { "RPL_ADMINLOC1", RPL_ADMINLOC1 }, - { "RPL_ADMINLOC2", RPL_ADMINLOC2 }, - { "RPL_ADMINEMAIL", RPL_ADMINEMAIL }, - { "RPL_TRACELOG", RPL_TRACELOG }, - { "RPL_TRACEEND", RPL_TRACEEND }, - { "RPL_TRYAGAIN", RPL_TRYAGAIN }, - { "RPL_NONE", RPL_NONE }, - { "RPL_AWAY", RPL_AWAY }, - { "RPL_USERHOST", RPL_USERHOST }, - { "RPL_ISON", RPL_ISON }, - { "RPL_UNAWAY", RPL_UNAWAY }, - { "RPL_NOWAWAY", RPL_NOWAWAY }, - { "RPL_WHOISUSER", RPL_WHOISUSER }, - { "RPL_WHOISSERVER", RPL_WHOISSERVER }, - { "RPL_WHOISOPERATOR", RPL_WHOISOPERATOR }, - { "RPL_WHOWASUSER", RPL_WHOWASUSER }, - { "RPL_ENDOFWHO", RPL_ENDOFWHO }, - { "RPL_WHOISIDLE", RPL_WHOISIDLE }, - { "RPL_ENDOFWHOIS", RPL_ENDOFWHOIS }, - { "RPL_WHOISCHANNELS", RPL_WHOISCHANNELS }, - { "RPL_LISTSTART", RPL_LISTSTART }, - { "RPL_LIST", RPL_LIST }, - { "RPL_LISTEND", RPL_LISTEND }, - { "RPL_CHANNELMODEIS", RPL_CHANNELMODEIS }, - { "RPL_UNIQOPIS", RPL_UNIQOPIS }, - { "RPL_NOTOPIC", RPL_NOTOPIC }, - { "RPL_TOPIC", RPL_TOPIC }, - { "RPL_INVITING", RPL_INVITING }, - { "RPL_SUMMONING", RPL_SUMMONING }, - { "RPL_INVITELIST", RPL_INVITELIST }, - { "RPL_ENDOFINVITELIST", RPL_ENDOFINVITELIST }, - { "RPL_EXCEPTLIST", RPL_EXCEPTLIST }, - { "RPL_ENDOFEXCEPTLIST", RPL_ENDOFEXCEPTLIST }, - { "RPL_VERSION", RPL_VERSION }, - { "RPL_WHOREPLY", RPL_WHOREPLY }, - { "RPL_NAMREPLY", RPL_NAMREPLY }, - { "RPL_KILLDONE", RPL_KILLDONE }, - { "RPL_CLOSEEND", RPL_CLOSEEND }, - { "RPL_LINKS", RPL_LINKS }, - { "RPL_ENDOFLINKS", RPL_ENDOFLINKS }, - { "RPL_ENDOFNAMES", RPL_ENDOFNAMES }, - { "RPL_BANLIST", RPL_BANLIST }, - { "RPL_ENDOFBANLIST", RPL_ENDOFBANLIST }, - { "RPL_ENDOFWHOWAS", RPL_ENDOFWHOWAS }, - { "RPL_INFO", RPL_INFO }, - { "RPL_MOTD", RPL_MOTD }, - { "RPL_ENDOFINFO", RPL_ENDOFINFO }, - { "RPL_MOTDSTART", RPL_MOTDSTART }, - { "RPL_ENDOFMOTD", RPL_ENDOFMOTD }, - { "RPL_YOUREOPER", RPL_YOUREOPER }, - { "RPL_REHASHING", RPL_REHASHING }, - { "RPL_YOURESERVICE", RPL_YOURESERVICE }, - { "RPL_MYPORTIS", RPL_MYPORTIS }, - { "RPL_TIME", RPL_TIME }, - { "RPL_USERSSTART", RPL_USERSSTART }, - { "RPL_USERS", RPL_USERS }, - { "RPL_ENDOFUSERS", RPL_ENDOFUSERS }, - { "RPL_NOUSERS", RPL_NOUSERS }, - { "ERR_NOSUCHNICK", ERR_NOSUCHNICK }, - { "ERR_NOSUCHSERVER", ERR_NOSUCHSERVER }, - { "ERR_NOSUCHCHANNEL", ERR_NOSUCHCHANNEL }, - { "ERR_CANNOTSENDTOCHAN", ERR_CANNOTSENDTOCHAN }, - { "ERR_TOOMANYCHANNELS", ERR_TOOMANYCHANNELS }, - { "ERR_WASNOSUCHNICK", ERR_WASNOSUCHNICK }, - { "ERR_TOOMANYTARGETS", ERR_TOOMANYTARGETS }, - { "ERR_NOSUCHSERVICE", ERR_NOSUCHSERVICE }, - { "ERR_NOORIGIN", ERR_NOORIGIN }, - { "ERR_NORECIPIENT", ERR_NORECIPIENT }, - { "ERR_NOTEXTTOSEND", ERR_NOTEXTTOSEND }, - { "ERR_NOTOPLEVEL", ERR_NOTOPLEVEL }, - { "ERR_WILDTOPLEVEL", ERR_WILDTOPLEVEL }, - { "ERR_BADMASK", ERR_BADMASK }, - { "ERR_UNKNOWNCOMMAND", ERR_UNKNOWNCOMMAND }, - { "ERR_NOMOTD", ERR_NOMOTD }, - { "ERR_NOADMININFO", ERR_NOADMININFO }, - { "ERR_FILEERROR", ERR_FILEERROR }, - { "ERR_NONICKNAMEGIVEN", ERR_NONICKNAMEGIVEN }, - { "ERR_ERRONEUSNICKNAME", ERR_ERRONEUSNICKNAME }, - { "ERR_NICKNAMEINUSE", ERR_NICKNAMEINUSE }, - { "ERR_NICKCOLLISION", ERR_NICKCOLLISION }, - { "ERR_UNAVAILRESOURCE", ERR_UNAVAILRESOURCE }, - { "ERR_USERNOTINCHANNEL", ERR_USERNOTINCHANNEL }, - { "ERR_NOTONCHANNEL", ERR_NOTONCHANNEL }, - { "ERR_USERONCHANNEL", ERR_USERONCHANNEL }, - { "ERR_NOLOGIN", ERR_NOLOGIN }, - { "ERR_SUMMONDISABLED", ERR_SUMMONDISABLED }, - { "ERR_USERSDISABLED", ERR_USERSDISABLED }, - { "ERR_NOTREGISTERED", ERR_NOTREGISTERED }, - { "ERR_NEEDMOREPARAMS", ERR_NEEDMOREPARAMS }, - { "ERR_ALREADYREGISTRED", ERR_ALREADYREGISTRED }, - { "ERR_NOPERMFORHOST", ERR_NOPERMFORHOST }, - { "ERR_PASSWDMISMATCH", ERR_PASSWDMISMATCH }, - { "ERR_YOUREBANNEDCREEP", ERR_YOUREBANNEDCREEP }, - { "ERR_YOUWILLBEBANNED", ERR_YOUWILLBEBANNED }, - { "ERR_KEYSET", ERR_KEYSET }, - { "ERR_CHANNELISFULL", ERR_CHANNELISFULL }, - { "ERR_UNKNOWNMODE", ERR_UNKNOWNMODE }, - { "ERR_INVITEONLYCHAN", ERR_INVITEONLYCHAN }, - { "ERR_BANNEDFROMCHAN", ERR_BANNEDFROMCHAN }, - { "ERR_BADCHANNELKEY", ERR_BADCHANNELKEY }, - { "ERR_BADCHANMASK", ERR_BADCHANMASK }, - { "ERR_NOCHANMODES", ERR_NOCHANMODES }, - { "ERR_BANLISTFULL", ERR_BANLISTFULL }, - { "ERR_NOPRIVILEGES", ERR_NOPRIVILEGES }, - { "ERR_CHANOPRIVSNEEDED", ERR_CHANOPRIVSNEEDED }, - { "ERR_CANTKILLSERVER", ERR_CANTKILLSERVER }, - { "ERR_RESTRICTED", ERR_RESTRICTED }, - { "ERR_UNIQOPPRIVSNEEDED", ERR_UNIQOPPRIVSNEEDED }, - { "ERR_NOOPERHOST", ERR_NOOPERHOST }, - { "ERR_NOSERVICEHOST", ERR_NOSERVICEHOST }, - { "ERR_UMODEUNKNOWNFLAG", ERR_UMODEUNKNOWNFLAG }, - { "ERR_USERSDONTMATCH", ERR_USERSDONTMATCH }, -}; - -Channel * Channel::start = 0; - -Channel::Channel(const String & Name, const String & Key) : next(0), prev(0) { - next = start->next; - prev = start; - start = this; - if (next) next->prev = this; -} - -Channel::~Channel() { - if (next) next->prev = prev; - if (prev) prev->next = next; else start = next; -} - -ircmsg_t find_msg(int code) { - int i; - - ircmsg_t ret = {"", code}; - - for (i = 0; i < MSG_COUNT; i++) { - if (code == ircmsgs[i].code) return ircmsgs[i]; - } - - return ret; -} - -IRC::IRC(const String & nick_n, const String & server_n, const String & user_n, const String & name_n, int port_n) : - nick(nick_n), server(server_n), user(user_n), name(name_n), port(port_n), loginsequence(1) { -} - -IRC::~IRC() { -} - -bool IRC::Connect() { - return sock.Connect(server, port); -} - -int IRC::Parse(const String & line) { - if (line.extract(0, 3) == "PING") { - sock << "PONG" << line.extract(4) << endhl; - std::cerr << "PING/PONG" << line.extract(4) << endhl; - return 0; - } - - return 1; -} - -void IRC::MainLoop() { - String line; - int code, count = 0; - - while (true) { - switch (loginsequence) { - case 1: - std::cerr << "Trying the login sequence..." << std::endl; - sock << "NICK " << nick << endhl; - sock << "USER " << user << " 8 * :" << name << endhl; - loginsequence = 0; - } - sock >> line; - if ((code = Parse(line))) { - std::cerr << "Unparsable: " << line << std::endl; - } - - if (count == 20) { - sock << "JOIN #linuxdjeunz" << endhl; - } - - count++; - } -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "BString.h"
+#include "IRC.h"
+#include "HttpServ.h"
+
+ircmsg_t ircmsgs[MSG_COUNT] =
+
+{
+ { "RPL_WELCOME", RPL_WELCOME },
+ { "RPL_YOURHOST", RPL_YOURHOST },
+ { "RPL_CREATED", RPL_CREATED },
+ { "RPL_MYINFO", RPL_MYINFO },
+ { "RPL_BOUNCE", RPL_BOUNCE },
+ { "RPL_TRACELINK", RPL_TRACELINK },
+ { "RPL_TRACECONNECTING", RPL_TRACECONNECTING },
+ { "RPL_TRACEHANDSHAKE", RPL_TRACEHANDSHAKE },
+ { "RPL_TRACEUNKNOWN", RPL_TRACEUNKNOWN },
+ { "RPL_TRACEOPERATOR", RPL_TRACEOPERATOR },
+ { "RPL_TRACEUSER", RPL_TRACEUSER },
+ { "RPL_TRACESERVER", RPL_TRACESERVER },
+ { "RPL_TRACESERVICE", RPL_TRACESERVICE },
+ { "RPL_TRACENEWTYPE", RPL_TRACENEWTYPE },
+ { "RPL_TRACECLASS", RPL_TRACECLASS },
+ { "RPL_TRACERECONNECT", RPL_TRACERECONNECT },
+ { "RPL_STATSLINKINFO", RPL_STATSLINKINFO },
+ { "RPL_STATSCOMMANDS", RPL_STATSCOMMANDS },
+ { "RPL_STATSCLINE", RPL_STATSCLINE },
+ { "RPL_STATSILINE", RPL_STATSILINE },
+ { "RPL_STATSQLINE", RPL_STATSQLINE },
+ { "RPL_ENDOFSTATS", RPL_ENDOFSTATS },
+ { "RPL_UMODEIS", RPL_UMODEIS },
+ { "RPL_SERVICEINFO", RPL_SERVICEINFO },
+ { "RPL_SERVICE", RPL_SERVICE },
+ { "RPL_SERVLIST", RPL_SERVLIST },
+ { "RPL_SERVLISTEND", RPL_SERVLISTEND },
+ { "RPL_STATSVLINE", RPL_STATSVLINE },
+ { "RPL_STATSUPTIME", RPL_STATSUPTIME },
+ { "RPL_STATSOLINE", RPL_STATSOLINE },
+ { "RPL_STATSHLINE", RPL_STATSHLINE },
+ { "RPL_STATSPING", RPL_STATSPING },
+ { "RPL_STATSDLINE", RPL_STATSDLINE },
+ { "RPL_LUSERCLIENT", RPL_LUSERCLIENT },
+ { "RPL_LUSEROP", RPL_LUSEROP },
+ { "RPL_LUSERUNKNOWN", RPL_LUSERUNKNOWN },
+ { "RPL_LUSERCHANNELS", RPL_LUSERCHANNELS },
+ { "RPL_LUSERME", RPL_LUSERME },
+ { "RPL_ADMINME", RPL_ADMINME },
+ { "RPL_ADMINLOC1", RPL_ADMINLOC1 },
+ { "RPL_ADMINLOC2", RPL_ADMINLOC2 },
+ { "RPL_ADMINEMAIL", RPL_ADMINEMAIL },
+ { "RPL_TRACELOG", RPL_TRACELOG },
+ { "RPL_TRACEEND", RPL_TRACEEND },
+ { "RPL_TRYAGAIN", RPL_TRYAGAIN },
+ { "RPL_NONE", RPL_NONE },
+ { "RPL_AWAY", RPL_AWAY },
+ { "RPL_USERHOST", RPL_USERHOST },
+ { "RPL_ISON", RPL_ISON },
+ { "RPL_UNAWAY", RPL_UNAWAY },
+ { "RPL_NOWAWAY", RPL_NOWAWAY },
+ { "RPL_WHOISUSER", RPL_WHOISUSER },
+ { "RPL_WHOISSERVER", RPL_WHOISSERVER },
+ { "RPL_WHOISOPERATOR", RPL_WHOISOPERATOR },
+ { "RPL_WHOWASUSER", RPL_WHOWASUSER },
+ { "RPL_ENDOFWHO", RPL_ENDOFWHO },
+ { "RPL_WHOISIDLE", RPL_WHOISIDLE },
+ { "RPL_ENDOFWHOIS", RPL_ENDOFWHOIS },
+ { "RPL_WHOISCHANNELS", RPL_WHOISCHANNELS },
+ { "RPL_LISTSTART", RPL_LISTSTART },
+ { "RPL_LIST", RPL_LIST },
+ { "RPL_LISTEND", RPL_LISTEND },
+ { "RPL_CHANNELMODEIS", RPL_CHANNELMODEIS },
+ { "RPL_UNIQOPIS", RPL_UNIQOPIS },
+ { "RPL_NOTOPIC", RPL_NOTOPIC },
+ { "RPL_TOPIC", RPL_TOPIC },
+ { "RPL_INVITING", RPL_INVITING },
+ { "RPL_SUMMONING", RPL_SUMMONING },
+ { "RPL_INVITELIST", RPL_INVITELIST },
+ { "RPL_ENDOFINVITELIST", RPL_ENDOFINVITELIST },
+ { "RPL_EXCEPTLIST", RPL_EXCEPTLIST },
+ { "RPL_ENDOFEXCEPTLIST", RPL_ENDOFEXCEPTLIST },
+ { "RPL_VERSION", RPL_VERSION },
+ { "RPL_WHOREPLY", RPL_WHOREPLY },
+ { "RPL_NAMREPLY", RPL_NAMREPLY },
+ { "RPL_KILLDONE", RPL_KILLDONE },
+ { "RPL_CLOSEEND", RPL_CLOSEEND },
+ { "RPL_LINKS", RPL_LINKS },
+ { "RPL_ENDOFLINKS", RPL_ENDOFLINKS },
+ { "RPL_ENDOFNAMES", RPL_ENDOFNAMES },
+ { "RPL_BANLIST", RPL_BANLIST },
+ { "RPL_ENDOFBANLIST", RPL_ENDOFBANLIST },
+ { "RPL_ENDOFWHOWAS", RPL_ENDOFWHOWAS },
+ { "RPL_INFO", RPL_INFO },
+ { "RPL_MOTD", RPL_MOTD },
+ { "RPL_ENDOFINFO", RPL_ENDOFINFO },
+ { "RPL_MOTDSTART", RPL_MOTDSTART },
+ { "RPL_ENDOFMOTD", RPL_ENDOFMOTD },
+ { "RPL_YOUREOPER", RPL_YOUREOPER },
+ { "RPL_REHASHING", RPL_REHASHING },
+ { "RPL_YOURESERVICE", RPL_YOURESERVICE },
+ { "RPL_MYPORTIS", RPL_MYPORTIS },
+ { "RPL_TIME", RPL_TIME },
+ { "RPL_USERSSTART", RPL_USERSSTART },
+ { "RPL_USERS", RPL_USERS },
+ { "RPL_ENDOFUSERS", RPL_ENDOFUSERS },
+ { "RPL_NOUSERS", RPL_NOUSERS },
+ { "ERR_NOSUCHNICK", ERR_NOSUCHNICK },
+ { "ERR_NOSUCHSERVER", ERR_NOSUCHSERVER },
+ { "ERR_NOSUCHCHANNEL", ERR_NOSUCHCHANNEL },
+ { "ERR_CANNOTSENDTOCHAN", ERR_CANNOTSENDTOCHAN },
+ { "ERR_TOOMANYCHANNELS", ERR_TOOMANYCHANNELS },
+ { "ERR_WASNOSUCHNICK", ERR_WASNOSUCHNICK },
+ { "ERR_TOOMANYTARGETS", ERR_TOOMANYTARGETS },
+ { "ERR_NOSUCHSERVICE", ERR_NOSUCHSERVICE },
+ { "ERR_NOORIGIN", ERR_NOORIGIN },
+ { "ERR_NORECIPIENT", ERR_NORECIPIENT },
+ { "ERR_NOTEXTTOSEND", ERR_NOTEXTTOSEND },
+ { "ERR_NOTOPLEVEL", ERR_NOTOPLEVEL },
+ { "ERR_WILDTOPLEVEL", ERR_WILDTOPLEVEL },
+ { "ERR_BADMASK", ERR_BADMASK },
+ { "ERR_UNKNOWNCOMMAND", ERR_UNKNOWNCOMMAND },
+ { "ERR_NOMOTD", ERR_NOMOTD },
+ { "ERR_NOADMININFO", ERR_NOADMININFO },
+ { "ERR_FILEERROR", ERR_FILEERROR },
+ { "ERR_NONICKNAMEGIVEN", ERR_NONICKNAMEGIVEN },
+ { "ERR_ERRONEUSNICKNAME", ERR_ERRONEUSNICKNAME },
+ { "ERR_NICKNAMEINUSE", ERR_NICKNAMEINUSE },
+ { "ERR_NICKCOLLISION", ERR_NICKCOLLISION },
+ { "ERR_UNAVAILRESOURCE", ERR_UNAVAILRESOURCE },
+ { "ERR_USERNOTINCHANNEL", ERR_USERNOTINCHANNEL },
+ { "ERR_NOTONCHANNEL", ERR_NOTONCHANNEL },
+ { "ERR_USERONCHANNEL", ERR_USERONCHANNEL },
+ { "ERR_NOLOGIN", ERR_NOLOGIN },
+ { "ERR_SUMMONDISABLED", ERR_SUMMONDISABLED },
+ { "ERR_USERSDISABLED", ERR_USERSDISABLED },
+ { "ERR_NOTREGISTERED", ERR_NOTREGISTERED },
+ { "ERR_NEEDMOREPARAMS", ERR_NEEDMOREPARAMS },
+ { "ERR_ALREADYREGISTRED", ERR_ALREADYREGISTRED },
+ { "ERR_NOPERMFORHOST", ERR_NOPERMFORHOST },
+ { "ERR_PASSWDMISMATCH", ERR_PASSWDMISMATCH },
+ { "ERR_YOUREBANNEDCREEP", ERR_YOUREBANNEDCREEP },
+ { "ERR_YOUWILLBEBANNED", ERR_YOUWILLBEBANNED },
+ { "ERR_KEYSET", ERR_KEYSET },
+ { "ERR_CHANNELISFULL", ERR_CHANNELISFULL },
+ { "ERR_UNKNOWNMODE", ERR_UNKNOWNMODE },
+ { "ERR_INVITEONLYCHAN", ERR_INVITEONLYCHAN },
+ { "ERR_BANNEDFROMCHAN", ERR_BANNEDFROMCHAN },
+ { "ERR_BADCHANNELKEY", ERR_BADCHANNELKEY },
+ { "ERR_BADCHANMASK", ERR_BADCHANMASK },
+ { "ERR_NOCHANMODES", ERR_NOCHANMODES },
+ { "ERR_BANLISTFULL", ERR_BANLISTFULL },
+ { "ERR_NOPRIVILEGES", ERR_NOPRIVILEGES },
+ { "ERR_CHANOPRIVSNEEDED", ERR_CHANOPRIVSNEEDED },
+ { "ERR_CANTKILLSERVER", ERR_CANTKILLSERVER },
+ { "ERR_RESTRICTED", ERR_RESTRICTED },
+ { "ERR_UNIQOPPRIVSNEEDED", ERR_UNIQOPPRIVSNEEDED },
+ { "ERR_NOOPERHOST", ERR_NOOPERHOST },
+ { "ERR_NOSERVICEHOST", ERR_NOSERVICEHOST },
+ { "ERR_UMODEUNKNOWNFLAG", ERR_UMODEUNKNOWNFLAG },
+ { "ERR_USERSDONTMATCH", ERR_USERSDONTMATCH },
+};
+
+Channel * Channel::start = 0;
+
+Channel::Channel(const String & Name, const String & Key) : next(0), prev(0) {
+ next = start->next;
+ prev = start;
+ start = this;
+ if (next) next->prev = this;
+}
+
+Channel::~Channel() {
+ if (next) next->prev = prev;
+ if (prev) prev->next = next; else start = next;
+}
+
+ircmsg_t find_msg(int code) {
+ int i;
+
+ ircmsg_t ret = {"", code};
+
+ for (i = 0; i < MSG_COUNT; i++) {
+ if (code == ircmsgs[i].code) return ircmsgs[i];
+ }
+
+ return ret;
+}
+
+IRC::IRC(const String & nick_n, const String & server_n, const String & user_n, const String & name_n, int port_n) :
+ nick(nick_n), server(server_n), user(user_n), name(name_n), port(port_n), loginsequence(1) {
+}
+
+IRC::~IRC() {
+}
+
+bool IRC::Connect() {
+ return sock.Connect(server, port);
+}
+
+int IRC::Parse(const String & line) {
+ if (line.extract(0, 3) == "PING") {
+ sock << "PONG" << line.extract(4) << endhl;
+ std::cerr << "PING/PONG" << line.extract(4) << endhl;
+ return 0;
+ }
+
+ return 1;
+}
+
+void IRC::MainLoop() {
+ String line;
+ int code, count = 0;
+
+ while (true) {
+ switch (loginsequence) {
+ case 1:
+ std::cerr << "Trying the login sequence..." << std::endl;
+ sock << "NICK " << nick << endhl;
+ sock << "USER " << user << " 8 * :" << name << endhl;
+ loginsequence = 0;
+ }
+ sock >> line;
+ if ((code = Parse(line))) {
+ std::cerr << "Unparsable: " << line << std::endl;
+ }
+
+ if (count == 20) {
+ sock << "JOIN #linuxdjeunz" << endhl;
+ }
+
+ count++;
+ }
+}
diff --git a/lib/Image.cc b/lib/Image.cc index d098de3..19d8aff 100644 --- a/lib/Image.cc +++ b/lib/Image.cc @@ -1,88 +1,88 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Image.h" -#include "gettext.h" - -Image::Image(unsigned int ax, unsigned int ay) : x(ax), y(ay), img((Color *) malloc(x * y * sizeof(Color))) { - Fill(); -} - -Image::~Image() { - free(img); -} - -bool Image::CanWrite() const { - return false; -} - -String Image::GetName() const { - return String(_("Image ")) + x + "x" + y; -} - -void Image::Fill(Color c) { - for (unsigned int i = 0; i < x * y; i++) { - img[i] = c; - } -} - -Color Image::GetPixel(unsigned int px, unsigned int py) const { - if ((px >= x) || (py >= y)) { - return Color(0, 0, 0, 0); - } - - return img[x * py + px]; -} - -void Image::SetPixel(unsigned int px, unsigned int py, Color c) { - if ((px >= x) || (py >= y)) { - return; - } - - img[x * py + px] = c; -} - -#ifndef WORDS_BIGENDIAN -#define WORDS_BIGENDIAN 0 -#else -#undef WORDS_BIGENDIAN -#define WORDS_BIGENDIAN 1 -#endif - -bool Image::Prepare(unsigned int f) { - if (GetSize()) return false; - - switch (f) { - case FORMAT_TGA_BASIC: - TGAHeader Header; - TGAFooter Footer; - - Header.IDLength = 0; - Header.ColorMapType = 0; - Header.ImageType = 2; - Header.CM_FirstEntry = 0; - Header.CM_Length = 0; - Header.CM_EntrySize = 0; - Header.IS_XOrigin = 0; - Header.IS_YOrigin = 0; - Header.IS_Width = WORDS_BIGENDIAN ? ((x & 0xff) << 8) | ((x & 0xff00) >> 8) : x; - Header.IS_Height = WORDS_BIGENDIAN ? ((y & 0xff) << 8) | ((y & 0xff00) >> 8) : y; - Header.IS_Depth = 32; - Header.IS_Descriptor = 0x20; - - Footer.ExtOffset = 0; - Footer.DevOffset = 0; - strcpy(Footer.Sig, "TRUEVISION-XFILE."); - - write(&Header, sizeof(Header)); - write(img, x * y * sizeof(Color)); - write(&Footer, sizeof(Footer)); - - return true; - - break; - default: - return false; - } -} - +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Image.h"
+#include "gettext.h"
+
+Image::Image(unsigned int ax, unsigned int ay) : x(ax), y(ay), img((Color *) malloc(x * y * sizeof(Color))) {
+ Fill();
+}
+
+Image::~Image() {
+ free(img);
+}
+
+bool Image::CanWrite() const {
+ return false;
+}
+
+String Image::GetName() const {
+ return String(_("Image ")) + x + "x" + y;
+}
+
+void Image::Fill(Color c) {
+ for (unsigned int i = 0; i < x * y; i++) {
+ img[i] = c;
+ }
+}
+
+Color Image::GetPixel(unsigned int px, unsigned int py) const {
+ if ((px >= x) || (py >= y)) {
+ return Color(0, 0, 0, 0);
+ }
+
+ return img[x * py + px];
+}
+
+void Image::SetPixel(unsigned int px, unsigned int py, Color c) {
+ if ((px >= x) || (py >= y)) {
+ return;
+ }
+
+ img[x * py + px] = c;
+}
+
+#ifndef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN 0
+#else
+#undef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN 1
+#endif
+
+bool Image::Prepare(unsigned int f) {
+ if (GetSize()) return false;
+
+ switch (f) {
+ case FORMAT_TGA_BASIC:
+ TGAHeader Header;
+ TGAFooter Footer;
+
+ Header.IDLength = 0;
+ Header.ColorMapType = 0;
+ Header.ImageType = 2;
+ Header.CM_FirstEntry = 0;
+ Header.CM_Length = 0;
+ Header.CM_EntrySize = 0;
+ Header.IS_XOrigin = 0;
+ Header.IS_YOrigin = 0;
+ Header.IS_Width = WORDS_BIGENDIAN ? ((x & 0xff) << 8) | ((x & 0xff00) >> 8) : x;
+ Header.IS_Height = WORDS_BIGENDIAN ? ((y & 0xff) << 8) | ((y & 0xff00) >> 8) : y;
+ Header.IS_Depth = 32;
+ Header.IS_Descriptor = 0x20;
+
+ Footer.ExtOffset = 0;
+ Footer.DevOffset = 0;
+ strcpy(Footer.Sig, "TRUEVISION-XFILE.");
+
+ write(&Header, sizeof(Header));
+ write(img, x * y * sizeof(Color));
+ write(&Footer, sizeof(Footer));
+
+ return true;
+
+ break;
+ default:
+ return false;
+ }
+}
+
diff --git a/lib/InPipe.cc b/lib/InPipe.cc index efcab10..fcbd1c6 100644 --- a/lib/InPipe.cc +++ b/lib/InPipe.cc @@ -1,42 +1,42 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "InPipe.h" -#include "Output.h" -#include "gettext.h" - -InPipe::InPipe() : Handle(pipe(p, 0)), hooked(0) { -} - -InPipe::InPipe(const InPipe & i) : Handle(i), hooked(i.hooked) { - p[0] = GetHandle(); - p[1] = dup(i.p[1]); -} - -InPipe::~InPipe() { - if (hooked) { - ::close(1); - dup(Stdout.GetHandle()); - } -} - -void InPipe::Hook() { - if (!hooked) { - hooked = 1; - ::close(1); - dup(p[1]); - ::close(p[1]); - } -} - -bool InPipe::CanWrite() { - return false; -} - -bool InPipe::CanRead() { - return true; -} - -String InPipe::GetName() { - return (String(_("Input pipe from stdout (")) + (hooked ? "" : _("not ")) + _("hooked)")); -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "InPipe.h"
+#include "Output.h"
+#include "gettext.h"
+
+InPipe::InPipe() : Handle(pipe(p, 0)), hooked(0) {
+}
+
+InPipe::InPipe(const InPipe & i) : Handle(i), hooked(i.hooked) {
+ p[0] = GetHandle();
+ p[1] = dup(i.p[1]);
+}
+
+InPipe::~InPipe() {
+ if (hooked) {
+ ::close(1);
+ dup(Stdout.GetHandle());
+ }
+}
+
+void InPipe::Hook() {
+ if (!hooked) {
+ hooked = 1;
+ ::close(1);
+ dup(p[1]);
+ ::close(p[1]);
+ }
+}
+
+bool InPipe::CanWrite() {
+ return false;
+}
+
+bool InPipe::CanRead() {
+ return true;
+}
+
+String InPipe::GetName() {
+ return (String(_("Input pipe from stdout (")) + (hooked ? "" : _("not ")) + _("hooked)"));
+}
diff --git a/lib/Input.cc b/lib/Input.cc index d6d9ebf..2e91e03 100644 --- a/lib/Input.cc +++ b/lib/Input.cc @@ -1,580 +1,580 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: Input.cc,v 1.47 2004-07-23 16:56:03 pixel Exp $ */ - -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#else -#include <io.h> -#endif - -#include "Input.h" -#include "Exceptions.h" -#include "gettext.h" - -#ifndef S_ISREG -#define S_ISREG(x) 1 -#endif - -#ifdef WORDS_BIGENDIAN -#define BUILTIN_SIG 0x4e504151 -#else -#define BUILTIN_SIG 0x5141504e -#endif - -/* - - NPAQ file format - ================ - -off|siz|description ----+---+----------- - 0 | 4 | Magic: NPAQ - 4 | X | Index -4+X| Y | Files - -Index: -It's composed of entries. Each entries have the same format: - -off|siz|description ----+---+----------- - 0 | 1 | name size = n - 1 | n | file name -1+n| 4 | file size -5+n| 1 | type --> 0 = file / 1 = directory - -If it's a directory, it means the following entries belongs to this directory. -If n = 0, there is nothing else afterward (no filesize nor type) and it -means the end of the current directory. The end of the root directory -means the end of the index. - -Files: -Each file are gzipped. They are all concatenated after the index. They -all start with a four bytes length which correspond to the unpacked size. -The size in the index corresponds to the size of the gzipped result plus -those 4 bytes. - -*/ - -static Input::openresults_t gresults; - -Input::Input(const String & no) throw (GeneralException) : - Handle(no.strlen() ? wrapopen(no, &gresults) : dup(0)), - n(no) { - -#ifdef DEBUG - printm(M_BARE, String(_("Opening file")) + no + _("Input at %p\n"), this); -#endif - - if (GetHandle() < 0) { -#ifdef DEBUG - printm(M_BARE, "Got handle: %i opening file " + no + "\n", GetHandle()); -#endif - throw IOGeneral(String(_("Error opening file ")) + no + _(" for reading: ") + strerror(errno)); - } - - results = gresults; - - UNLOCK - - fromarchive = false; - if (results.name == "") { - struct stat s; - fstat(GetHandle(), &s); - date_modif = s.st_mtime; - -#ifdef __linux__ - if (S_ISREG(s.st_mode)) { -#endif -#if 0 -#if defined (_WIN32) && !defined (NO_HFILE) - if (hFile) { - GetFileSize(hFile, (LPDWORD)&size); - } else -#endif -#endif - { - size = seek(0, SEEK_END); - seek(0, SEEK_SET); - } -#ifdef __linux__ - } -#endif - } else { -#ifdef DEBUG - printm(M_INFO, String(_("Opening file in archive, position ")) + results.ptr + "\n"); -#endif - size = results.size; - seek(results.ptr, SEEK_SET); - size = readU32(); - date_modif = 0; - SetZ(); - fromarchive = true; - itell = 0; - } -} - -Input::Input(const Input & i) : Handle(i), n(i.n), size(i.size), date_modif(i.date_modif) { -} - -bool Input::CanWrite() const { - return 0; -} - -bool Input::CanRead() const { - return 1; -} - -bool Input::CanSeek() const { - struct stat s; - - fstat(GetHandle(), &s); - - return S_ISREG(s.st_mode); -} - -String Input::GetName() const { - return n; -} - -ssize_t Input::GetSize() const { - return size; -} - -time_t Input::GetModif() const { - return date_modif; -} - -off_t Input::seek(off_t offset, int whence) throw (GeneralException) { - if (!fromarchive) { - if ((itell = lseek(GetHandle(), offset, whence)) < 0) { - throw IOGeneral(String(_("Error seeking file ")) + GetName() + _(": ") + strerror(errno)); - } -#ifdef PARANOID_SEEK - if (itell != lseek(GetHandle(), 0, SEEK_CUR)) { - throw IOGeneral(String(_("Error seeking file ")) + GetName() + _(": the position does not match")); - } -#endif - return itell; - } else { - return Handle::seek(offset, whence); - } -} - -int Input::wrapopen(const String & fname, openresults_t * results) { - LOCK; -#ifdef DEBUG - printm(M_INFO, _("Wrap-opening ") + fname + "\n"); -#endif - if (fname[0] != '/') { - Archive * t; - t = Archive::inarchive(fname); - if (t) { -#ifdef DEBUG - printm(M_BARE, _("Trying to open the file in archive, since it seems to be here\n")); -#endif - hFile = 0; -#if defined (_WIN32) && !defined (NO_HFILE) -// hFile = t->GetHandle()->GetHFile(); -#endif - return t->open(fname, results); - } - } - results->name = ""; - hFile = 0; -#if !defined (_WIN32) || defined (NO_HFILE) - return open(fname.to_charp(), O_RDONLY -#ifdef _WIN32 - | O_BINARY -#endif - ); -#else - hFile = CreateFile(fname.to_charp(), GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - return _open_osfhandle((INT_PTR) hFile, O_RDONLY | O_BINARY); -#endif -} - -void Input::SetZ(int l) throw(GeneralException) { - if (!fromarchive) - Handle::SetZ(l); -} - -Stdin_t::Stdin_t() { } - -bool Stdin_t::CanSeek() const { - return 0; -} - -String Stdin_t::GetName() const { - return "Stdin"; -} - -#ifdef HOOK_STDS -Stdin_t Stdin; -#endif - -Archive * Archive::header = 0; - -Archive::Archive(const String & fname, int atype) : - name(fname), archive(new Input(fname)), type(atype) { - create(); -} - -Archive::Archive(Handle * hand, int atype) : - name(hand->GetName()), archive(hand), type(atype) { - create(); -} - -#ifdef _MSC_VER -#pragma pack(1) -#endif - -struct PEsection_t { - char name[8]; - Uint32 VSize, VAdd, SizeOf, Pointer, PTRelocs, PTLNs; - Uint16 NR, NLN; - Uint32 Chars; -} PACKED; - -struct elf_header_t { - union { - Uint8 raw[16]; - struct e_ident_t { - Uint8 ei_magic[4]; - Uint8 ei_class; - Uint8 ei_data; - Uint8 ei_version; - } cook; - } e_ident; - Uint16 e_type; - Uint16 e_machine; - Uint32 e_version; - Uint32 e_entry; - Uint32 e_phoff; - Uint32 e_shoff; - Uint32 e_flags; - Uint16 e_ehsize; - Uint16 e_phentsize; - Uint16 e_phnum; - Uint16 e_shentsize; - Uint16 e_shnum; - Uint16 e_shstrndx; -} PACKED; - -struct elf_section_t { - Uint32 sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size; - Uint32 sh_link, sh_info, sh_addralign, sh_entsize; -} PACKED; - -void Archive::create() throw (GeneralException) { - char buffer[1024]; - int len; - Uint32 sig, ptr, maxptr = 0, startptr; - Uint16 sections; - PEsection_t PEsection; - size_t size; - FileTree * p = &filetree, * t; - String ifname; - int i; - - switch(type) { - case ARCHIVE_EXECUTABLE: - startptr = archive->tell(); - sig = archive->readU32(); - archive->seek(-4, SEEK_CUR); - if ((sig & 0xffff) == 0x5a4d) { /* MZ */ - archive->seek(60, SEEK_CUR); - sig = archive->readU32(); - archive->seek(sig - 64, SEEK_CUR); - sig = archive->readU32(); - if (sig != 0x4550) - throw GeneralException(_("Archive: file is not a PE.")); - archive->seek(2, SEEK_CUR); - sections = archive->readU16(); - archive->seek(240, SEEK_CUR); - for (i = 0; i < sections; i++) { - archive->read(&PEsection, sizeof(PEsection)); - printm(M_INFO, "Section: %s\n", PEsection.name); - ptr = PEsection.Pointer + PEsection.SizeOf; - if (ptr > maxptr) - maxptr = ptr; - } - archive->seek(startptr - archive->tell() + maxptr, SEEK_CUR); - } else if (sig == 0x464c457f) { /* ELF */ - elf_header_t head; - elf_section_t sec; - int cur_end, max_end = 0; - int i; - - archive->read(&head, sizeof(head)); - archive->seek(startptr + head.e_shoff); - - for (i = 0; i < head.e_shnum; i++) { - archive->read(&sec, sizeof(elf_section_t)); - archive->seek(head.e_shentsize - sizeof(elf_section_t), SEEK_CUR); - if (sec.sh_type == 8) - continue; - cur_end = sec.sh_offset + sec.sh_size; - if (cur_end > max_end) - max_end = cur_end; - } - archive->seek(startptr + max_end); - } - case ARCHIVE_BUILTIN: - memset(buffer, 0, 4); - archive->read(buffer, 4); - if (*((Uint32 *)buffer) != BUILTIN_SIG) - throw GeneralException(_("Archive: not in built-in format.")); - while (p) { - archive->read(buffer, 1); - len = *buffer; - if (len) { - archive->read(buffer, len); - buffer[len] = 0; - ifname = buffer; - size = archive->readU32(); - archive->read(buffer, 1); -#ifdef DEBUG - printm(M_BARE, _("Adding file `") + ifname + _("' to node `") + p->name + "'\n"); -#endif - t = new FileTree(ifname, size, buffer[0], p); - if (buffer[0]) - p = t; - } else { - p = p->Father(); - } - } - filetree.compute_ptrs(archive->tell()); - break; - default: - throw GeneralException(_("Archive: unsupported archive format.")); - } - - next = header; - prev = 0; - header = this; - if (next) - next->prev = this; -} - -Archive::~Archive() { - if (prev) - prev->next = next; - if (next) - next->prev = prev; - if (header == this) - header = next; - - delete archive; -} - -Archive * Archive::inarchive(const String & fname) { - Archive * p; - for (p = header; p; p = p->next) { -#ifdef DEBUG - printm(M_BARE, _("Looking for file `") + fname + _("' in archive ") + p->name + "\n"); -#endif - if (p->inarchivein(fname)) { -#ifdef DEBUG - printm(M_BARE, _("File `") + fname + _("' found in archive ") + p->name + "\n"); -#endif - return p; - } - } - return 0; -} - -int Archive::open(const String & fname, Input::openresults_t * results) { -#if 0 - Archive * p; - - for (p = header; p; p = p->next) { - bool t; - t = p->inarchive(fname); - if (t) - return p->openin(fname, results); - } - throw IOGeneral(_("File `") + fname + _("' not found in archive collection.")); -#endif - return openin(fname, results); -} - -Handle * Archive::GetHandle() { - return archive; -} - -bool Archive::inarchivein(const String & fname) { - Archive::FileTree * p = filetree.Child(); - ssize_t pos; - String name = fname; - String reste; - - while((name != "") && p) { - pos = name.strchr('/'); - if (pos >= 0) { - reste = name.extract(0, pos - 1); - name = name.extract(pos + 1); - } else { - reste = name; - name = ""; - } -#ifdef DEBUG - printm(M_BARE, _("Checking against node `") + p->name + "'\n"); -#endif - while (p) { - if (p->name == reste) { - if (name != "") - p = p->Child(); - break; - } else { - p = p->Next(); - } - } - } - - return p != 0; -} - -int Archive::openin(const String & fname, Input::openresults_t * results) throw (GeneralException) { - Archive::FileTree * p = filetree.Child(); - ssize_t pos; - String name = fname; - String reste; - - while((name != "") && p) { - pos = name.strchr('/'); - if (pos >= 0) { - reste = name.extract(0, pos - 1); - name = name.extract(pos + 1); - } else { - reste = name; - name = ""; - } - - while (p) { - if (p->name == reste) { - if (name != "") - p = p->Child(); - break; - } else { - p = p->Next(); - } - } - } - - if (!p) - throw IOGeneral(_("File `") + fname + _("' not in archive ") + this->name); - - if (p->Child()) - throw IOGeneral(_("File `") + fname + _("' in archive ") + this->name + _(" is a directory - can't open.")); - - results->name = p->name; - results->ptr = p->ptr; - results->size = p->size; - results->type = p->type; - return archive->Dup(); -} - -Archive::FileTree::FileTree(const String & fname, size_t fsize, int ftype, Archive::FileTree * fFather) : - name(fname), type(ftype), size(fsize), next(0), prev(0), father(fFather), child(0) { - if (father) { - if (father->child) { - FileTree * p; - for (p = father->child; p->next; p = p->next); - p->next = this; - prev = p; - } else { -#ifdef DEBUG - std::cerr << _("Adding `") << fname << _("' as first child of node `") << father->name << "'\n"; -#endif - father->child = this; - } - } -} - -Archive::FileTree::~FileTree() { - if (child) - delete child; - if (next) - next->prev = prev; - if (prev) - prev->next = next; - if (father) { - if (father->child == this) - father->child = next; - father->touched(); - } -} - -void Archive::FileTree::touched() { - if (father) - father->touched(); - else - compute_ptrs(ptr); -} - -int Archive::FileTree::compute_ptrs(size_t cptr) { - ptr = cptr; - -#ifdef DEBUG - std::cerr << _("Computed pointer for `") << name << "' = " << ptr << std::endl; - if (child) - std::cerr << _("Node has child\n"); - else - std::cerr << _("Node is ") << size << _(" bytes large.\n"); -#endif - - if (child) { - FileTree * p; - size = 0; - for (p = child; p; p = p->next) { - size = p->compute_ptrs(ptr + size) - ptr; - } - } - - return size + ptr; -} - -Archive::FileTree * Archive::FileTree::Father() { - return father; -} - -Archive::FileTree * Archive::FileTree::Child() { - return child; -} - -Archive::FileTree * Archive::FileTree::Next() { - return next; -} - -Archive::FileTree * Archive::FileTree::Prev() { - return prev; -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: Input.cc,v 1.48 2004-11-27 21:35:19 pixel Exp $ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "Input.h"
+#include "Exceptions.h"
+#include "gettext.h"
+
+#ifndef S_ISREG
+#define S_ISREG(x) 1
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define BUILTIN_SIG 0x4e504151
+#else
+#define BUILTIN_SIG 0x5141504e
+#endif
+
+/*
+
+ NPAQ file format
+ ================
+
+off|siz|description
+---+---+-----------
+ 0 | 4 | Magic: NPAQ
+ 4 | X | Index
+4+X| Y | Files
+
+Index:
+It's composed of entries. Each entries have the same format:
+
+off|siz|description
+---+---+-----------
+ 0 | 1 | name size = n
+ 1 | n | file name
+1+n| 4 | file size
+5+n| 1 | type --> 0 = file / 1 = directory
+
+If it's a directory, it means the following entries belongs to this directory.
+If n = 0, there is nothing else afterward (no filesize nor type) and it
+means the end of the current directory. The end of the root directory
+means the end of the index.
+
+Files:
+Each file are gzipped. They are all concatenated after the index. They
+all start with a four bytes length which correspond to the unpacked size.
+The size in the index corresponds to the size of the gzipped result plus
+those 4 bytes.
+
+*/
+
+static Input::openresults_t gresults;
+
+Input::Input(const String & no) throw (GeneralException) :
+ Handle(no.strlen() ? wrapopen(no, &gresults) : dup(0)),
+ n(no) {
+
+#ifdef DEBUG
+ printm(M_BARE, String(_("Opening file")) + no + _("Input at %p\n"), this);
+#endif
+
+ if (GetHandle() < 0) {
+#ifdef DEBUG
+ printm(M_BARE, "Got handle: %i opening file " + no + "\n", GetHandle());
+#endif
+ throw IOGeneral(String(_("Error opening file ")) + no + _(" for reading: ") + strerror(errno));
+ }
+
+ results = gresults;
+
+ UNLOCK
+
+ fromarchive = false;
+ if (results.name == "") {
+ struct stat s;
+ fstat(GetHandle(), &s);
+ date_modif = s.st_mtime;
+
+#ifdef __linux__
+ if (S_ISREG(s.st_mode)) {
+#endif
+#if 0
+#if defined (_WIN32) && !defined (NO_HFILE)
+ if (hFile) {
+ GetFileSize(hFile, (LPDWORD)&size);
+ } else
+#endif
+#endif
+ {
+ size = seek(0, SEEK_END);
+ seek(0, SEEK_SET);
+ }
+#ifdef __linux__
+ }
+#endif
+ } else {
+#ifdef DEBUG
+ printm(M_INFO, String(_("Opening file in archive, position ")) + results.ptr + "\n");
+#endif
+ size = results.size;
+ seek(results.ptr, SEEK_SET);
+ size = readU32();
+ date_modif = 0;
+ SetZ();
+ fromarchive = true;
+ itell = 0;
+ }
+}
+
+Input::Input(const Input & i) : Handle(i), n(i.n), size(i.size), date_modif(i.date_modif) {
+}
+
+bool Input::CanWrite() const {
+ return 0;
+}
+
+bool Input::CanRead() const {
+ return 1;
+}
+
+bool Input::CanSeek() const {
+ struct stat s;
+
+ fstat(GetHandle(), &s);
+
+ return S_ISREG(s.st_mode);
+}
+
+String Input::GetName() const {
+ return n;
+}
+
+ssize_t Input::GetSize() const {
+ return size;
+}
+
+time_t Input::GetModif() const {
+ return date_modif;
+}
+
+off_t Input::seek(off_t offset, int whence) throw (GeneralException) {
+ if (!fromarchive) {
+ if ((itell = lseek(GetHandle(), offset, whence)) < 0) {
+ throw IOGeneral(String(_("Error seeking file ")) + GetName() + _(": ") + strerror(errno));
+ }
+#ifdef PARANOID_SEEK
+ if (itell != lseek(GetHandle(), 0, SEEK_CUR)) {
+ throw IOGeneral(String(_("Error seeking file ")) + GetName() + _(": the position does not match"));
+ }
+#endif
+ return itell;
+ } else {
+ return Handle::seek(offset, whence);
+ }
+}
+
+int Input::wrapopen(const String & fname, openresults_t * results) {
+ LOCK;
+#ifdef DEBUG
+ printm(M_INFO, _("Wrap-opening ") + fname + "\n");
+#endif
+ if (fname[0] != '/') {
+ Archive * t;
+ t = Archive::inarchive(fname);
+ if (t) {
+#ifdef DEBUG
+ printm(M_BARE, _("Trying to open the file in archive, since it seems to be here\n"));
+#endif
+ hFile = 0;
+#if defined (_WIN32) && !defined (NO_HFILE)
+// hFile = t->GetHandle()->GetHFile();
+#endif
+ return t->open(fname, results);
+ }
+ }
+ results->name = "";
+ hFile = 0;
+#if !defined (_WIN32) || defined (NO_HFILE)
+ return open(fname.to_charp(), O_RDONLY
+#ifdef _WIN32
+ | O_BINARY
+#endif
+ );
+#else
+ hFile = CreateFile(fname.to_charp(), GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ return _open_osfhandle((INT_PTR) hFile, O_RDONLY | O_BINARY);
+#endif
+}
+
+void Input::SetZ(int l) throw(GeneralException) {
+ if (!fromarchive)
+ Handle::SetZ(l);
+}
+
+Stdin_t::Stdin_t() { }
+
+bool Stdin_t::CanSeek() const {
+ return 0;
+}
+
+String Stdin_t::GetName() const {
+ return "Stdin";
+}
+
+#ifdef HOOK_STDS
+Stdin_t Stdin;
+#endif
+
+Archive * Archive::header = 0;
+
+Archive::Archive(const String & fname, int atype) :
+ name(fname), archive(new Input(fname)), type(atype) {
+ create();
+}
+
+Archive::Archive(Handle * hand, int atype) :
+ name(hand->GetName()), archive(hand), type(atype) {
+ create();
+}
+
+#ifdef _MSC_VER
+#pragma pack(1)
+#endif
+
+struct PEsection_t {
+ char name[8];
+ Uint32 VSize, VAdd, SizeOf, Pointer, PTRelocs, PTLNs;
+ Uint16 NR, NLN;
+ Uint32 Chars;
+} PACKED;
+
+struct elf_header_t {
+ union {
+ Uint8 raw[16];
+ struct e_ident_t {
+ Uint8 ei_magic[4];
+ Uint8 ei_class;
+ Uint8 ei_data;
+ Uint8 ei_version;
+ } cook;
+ } e_ident;
+ Uint16 e_type;
+ Uint16 e_machine;
+ Uint32 e_version;
+ Uint32 e_entry;
+ Uint32 e_phoff;
+ Uint32 e_shoff;
+ Uint32 e_flags;
+ Uint16 e_ehsize;
+ Uint16 e_phentsize;
+ Uint16 e_phnum;
+ Uint16 e_shentsize;
+ Uint16 e_shnum;
+ Uint16 e_shstrndx;
+} PACKED;
+
+struct elf_section_t {
+ Uint32 sh_name, sh_type, sh_flags, sh_addr, sh_offset, sh_size;
+ Uint32 sh_link, sh_info, sh_addralign, sh_entsize;
+} PACKED;
+
+void Archive::create() throw (GeneralException) {
+ char buffer[1024];
+ int len;
+ Uint32 sig, ptr, maxptr = 0, startptr;
+ Uint16 sections;
+ PEsection_t PEsection;
+ size_t size;
+ FileTree * p = &filetree, * t;
+ String ifname;
+ int i;
+
+ switch(type) {
+ case ARCHIVE_EXECUTABLE:
+ startptr = archive->tell();
+ sig = archive->readU32();
+ archive->seek(-4, SEEK_CUR);
+ if ((sig & 0xffff) == 0x5a4d) { /* MZ */
+ archive->seek(60, SEEK_CUR);
+ sig = archive->readU32();
+ archive->seek(sig - 64, SEEK_CUR);
+ sig = archive->readU32();
+ if (sig != 0x4550)
+ throw GeneralException(_("Archive: file is not a PE."));
+ archive->seek(2, SEEK_CUR);
+ sections = archive->readU16();
+ archive->seek(240, SEEK_CUR);
+ for (i = 0; i < sections; i++) {
+ archive->read(&PEsection, sizeof(PEsection));
+ printm(M_INFO, "Section: %s\n", PEsection.name);
+ ptr = PEsection.Pointer + PEsection.SizeOf;
+ if (ptr > maxptr)
+ maxptr = ptr;
+ }
+ archive->seek(startptr - archive->tell() + maxptr, SEEK_CUR);
+ } else if (sig == 0x464c457f) { /* ELF */
+ elf_header_t head;
+ elf_section_t sec;
+ int cur_end, max_end = 0;
+ int i;
+
+ archive->read(&head, sizeof(head));
+ archive->seek(startptr + head.e_shoff);
+
+ for (i = 0; i < head.e_shnum; i++) {
+ archive->read(&sec, sizeof(elf_section_t));
+ archive->seek(head.e_shentsize - sizeof(elf_section_t), SEEK_CUR);
+ if (sec.sh_type == 8)
+ continue;
+ cur_end = sec.sh_offset + sec.sh_size;
+ if (cur_end > max_end)
+ max_end = cur_end;
+ }
+ archive->seek(startptr + max_end);
+ }
+ case ARCHIVE_BUILTIN:
+ memset(buffer, 0, 4);
+ archive->read(buffer, 4);
+ if (*((Uint32 *)buffer) != BUILTIN_SIG)
+ throw GeneralException(_("Archive: not in built-in format."));
+ while (p) {
+ archive->read(buffer, 1);
+ len = *buffer;
+ if (len) {
+ archive->read(buffer, len);
+ buffer[len] = 0;
+ ifname = buffer;
+ size = archive->readU32();
+ archive->read(buffer, 1);
+#ifdef DEBUG
+ printm(M_BARE, _("Adding file `") + ifname + _("' to node `") + p->name + "'\n");
+#endif
+ t = new FileTree(ifname, size, buffer[0], p);
+ if (buffer[0])
+ p = t;
+ } else {
+ p = p->Father();
+ }
+ }
+ filetree.compute_ptrs(archive->tell());
+ break;
+ default:
+ throw GeneralException(_("Archive: unsupported archive format."));
+ }
+
+ next = header;
+ prev = 0;
+ header = this;
+ if (next)
+ next->prev = this;
+}
+
+Archive::~Archive() {
+ if (prev)
+ prev->next = next;
+ if (next)
+ next->prev = prev;
+ if (header == this)
+ header = next;
+
+ delete archive;
+}
+
+Archive * Archive::inarchive(const String & fname) {
+ Archive * p;
+ for (p = header; p; p = p->next) {
+#ifdef DEBUG
+ printm(M_BARE, _("Looking for file `") + fname + _("' in archive ") + p->name + "\n");
+#endif
+ if (p->inarchivein(fname)) {
+#ifdef DEBUG
+ printm(M_BARE, _("File `") + fname + _("' found in archive ") + p->name + "\n");
+#endif
+ return p;
+ }
+ }
+ return 0;
+}
+
+int Archive::open(const String & fname, Input::openresults_t * results) {
+#if 0
+ Archive * p;
+
+ for (p = header; p; p = p->next) {
+ bool t;
+ t = p->inarchive(fname);
+ if (t)
+ return p->openin(fname, results);
+ }
+ throw IOGeneral(_("File `") + fname + _("' not found in archive collection."));
+#endif
+ return openin(fname, results);
+}
+
+Handle * Archive::GetHandle() {
+ return archive;
+}
+
+bool Archive::inarchivein(const String & fname) {
+ Archive::FileTree * p = filetree.Child();
+ ssize_t pos;
+ String name = fname;
+ String reste;
+
+ while((name != "") && p) {
+ pos = name.strchr('/');
+ if (pos >= 0) {
+ reste = name.extract(0, pos - 1);
+ name = name.extract(pos + 1);
+ } else {
+ reste = name;
+ name = "";
+ }
+#ifdef DEBUG
+ printm(M_BARE, _("Checking against node `") + p->name + "'\n");
+#endif
+ while (p) {
+ if (p->name == reste) {
+ if (name != "")
+ p = p->Child();
+ break;
+ } else {
+ p = p->Next();
+ }
+ }
+ }
+
+ return p != 0;
+}
+
+int Archive::openin(const String & fname, Input::openresults_t * results) throw (GeneralException) {
+ Archive::FileTree * p = filetree.Child();
+ ssize_t pos;
+ String name = fname;
+ String reste;
+
+ while((name != "") && p) {
+ pos = name.strchr('/');
+ if (pos >= 0) {
+ reste = name.extract(0, pos - 1);
+ name = name.extract(pos + 1);
+ } else {
+ reste = name;
+ name = "";
+ }
+
+ while (p) {
+ if (p->name == reste) {
+ if (name != "")
+ p = p->Child();
+ break;
+ } else {
+ p = p->Next();
+ }
+ }
+ }
+
+ if (!p)
+ throw IOGeneral(_("File `") + fname + _("' not in archive ") + this->name);
+
+ if (p->Child())
+ throw IOGeneral(_("File `") + fname + _("' in archive ") + this->name + _(" is a directory - can't open."));
+
+ results->name = p->name;
+ results->ptr = p->ptr;
+ results->size = p->size;
+ results->type = p->type;
+ return archive->Dup();
+}
+
+Archive::FileTree::FileTree(const String & fname, size_t fsize, int ftype, Archive::FileTree * fFather) :
+ name(fname), type(ftype), size(fsize), next(0), prev(0), father(fFather), child(0) {
+ if (father) {
+ if (father->child) {
+ FileTree * p;
+ for (p = father->child; p->next; p = p->next);
+ p->next = this;
+ prev = p;
+ } else {
+#ifdef DEBUG
+ std::cerr << _("Adding `") << fname << _("' as first child of node `") << father->name << "'\n";
+#endif
+ father->child = this;
+ }
+ }
+}
+
+Archive::FileTree::~FileTree() {
+ if (child)
+ delete child;
+ if (next)
+ next->prev = prev;
+ if (prev)
+ prev->next = next;
+ if (father) {
+ if (father->child == this)
+ father->child = next;
+ father->touched();
+ }
+}
+
+void Archive::FileTree::touched() {
+ if (father)
+ father->touched();
+ else
+ compute_ptrs(ptr);
+}
+
+int Archive::FileTree::compute_ptrs(size_t cptr) {
+ ptr = cptr;
+
+#ifdef DEBUG
+ std::cerr << _("Computed pointer for `") << name << "' = " << ptr << std::endl;
+ if (child)
+ std::cerr << _("Node has child\n");
+ else
+ std::cerr << _("Node is ") << size << _(" bytes large.\n");
+#endif
+
+ if (child) {
+ FileTree * p;
+ size = 0;
+ for (p = child; p; p = p->next) {
+ size = p->compute_ptrs(ptr + size) - ptr;
+ }
+ }
+
+ return size + ptr;
+}
+
+Archive::FileTree * Archive::FileTree::Father() {
+ return father;
+}
+
+Archive::FileTree * Archive::FileTree::Child() {
+ return child;
+}
+
+Archive::FileTree * Archive::FileTree::Next() {
+ return next;
+}
+
+Archive::FileTree * Archive::FileTree::Prev() {
+ return prev;
+}
diff --git a/lib/LuaHandle.cc b/lib/LuaHandle.cc index 3c7460d..a363cdc 100644 --- a/lib/LuaHandle.cc +++ b/lib/LuaHandle.cc @@ -1,680 +1,680 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: LuaHandle.cc,v 1.13 2004-02-16 13:16:52 pixel Exp $ */ - -#include "LuaHandle.h" - -LuaInput::LuaInput(Input * h) : LuaHandle(h) { } -LuaOutput::LuaOutput(Output * h) : LuaHandle(h) { } -LuaBuffer::LuaBuffer(Buffer * h) : LuaHandle(h) { } -LuaHandle::LuaHandle(Handle * _h) : h(_h) { } - -class sLuaHandle : public Base { - public: - static int newinput(lua_State * L); - static int newoutput(lua_State * L); - static int newbuffer(lua_State * L); - static int read(lua_State * L); - static int readstring(lua_State * L); - static int readU8(lua_State * L); - static int readU16(lua_State * L); - static int readU32(lua_State * L); - static int write(lua_State * L); - static int writestring(lua_State * L); - static int writeU8(lua_State * L); - static int writeU16(lua_State * L); - static int writeU32(lua_State * L); - static int copyfrom(lua_State * L); - static int copyto(lua_State * L); - static int isclosed(lua_State * L); - static int isnonblock(lua_State * L); - static int canread(lua_State * L); - static int canwrite(lua_State * L); - static int canseek(lua_State * L); - static int canwatch(lua_State * L); - static int setnonblock(lua_State * L); - static int tell(lua_State * L); - static int getname(lua_State * L); - static int getsize(lua_State * L); - static int getmodif(lua_State * L); - static int close(lua_State * L); - static int flush(lua_State * L); - static int seek(lua_State * L); - static int setz(lua_State * L); - static int bindex(lua_State * L); - static int bnewindex(lua_State * L); - static int bseek(lua_State * L); - static int btell(lua_State * L); - static int exists(lua_State * L); - private: - static int read(lua_State * L, int); - static int write(lua_State * L, int); - static int copy(lua_State * L, int); - static int getcaps(lua_State * L, int); - static int action(lua_State * L, int); - enum { - U8, U16, U32 - }; - enum { - from, to - }; - enum { - capisclosed, capisnonblock, capcanread, capcanwrite, capcanseek, capcanwatch - }; - enum { - Asetnonblock, Atell, Agetname, Agetsize, Agetmodif, Aclose, Aflush - }; -}; - -void LuaInput::pushconstruct(Lua * L) { - L->declarefunc("Input", sLuaHandle::newinput); -} - -void LuaOutput::pushconstruct(Lua * L) { - L->declarefunc("Output", sLuaHandle::newoutput); -} - -void LuaBuffer::pushconstruct(Lua * L) { - L->declarefunc("Buffer", sLuaHandle::newbuffer); -} - -int sLuaHandle::newinput(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - - if ((n != 1) || !L->isstring()) { - L->error("Incorrect arguments to constructor `Input'"); - } - - LuaInput i(new Input(L->tostring())); - i.pushdestruct(L); - - return 1; -} - -int sLuaHandle::newoutput(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - - if ((n != 1) || !L->isstring()) { - L->error("Incorrect arguments to constructor `Input'"); - } - - LuaOutput o(new Output(L->tostring())); - o.pushdestruct(L); - - return 1; -} - -int sLuaHandle::newbuffer(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - bool seekable = false; - - if ((n > 1) || ((n == 1) && (!L->isboolean()))) { - L->error("Incorrect arguments to constructor `Buffer'"); - } - - if (n == 1) - seekable = L->toboolean(); - - LuaBuffer o(new Buffer(seekable)); - o.pushdestruct(L); - - return 1; -} - -int sLuaHandle::read(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(), i; - size_t t; - ssize_t r; - Handle * h; - Byte * b; - - if (n == 1) { - return readstring(_L); - } - - if ((n != 2) || !L->isnumber()) { - L->error("Incorrect arguments to method `Headle::read'"); - } - - t = L->tonumber(); - b = (Byte *) malloc(t); - h = (Handle *) LuaObject::getme(L); - - L->newtable(); - - r = h->read(b, t); - - for (i = 0; i < r; i++) { - L->push((lua_Number) i); - L->push((lua_Number) b[i]); - L->settable(); - } - - free(b); - - L->push((lua_Number) r); - - return 2; -} - -int sLuaHandle::readstring(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(), i; - Handle * h; - String r; - - if (n != 1) { - L->error("Incorrect arguments to method `Headle::readstring'"); - } - - h = (Handle *) LuaObject::getme(L); - - (*h) >> r; - - L->push(r); - - return 1; -} - -int sLuaHandle::readU8(lua_State * L) { - return read(L, U8); -} - -int sLuaHandle::readU16(lua_State * L) { - return read(L, U16); -} - -int sLuaHandle::readU32(lua_State * L) { - return read(L, U32); -} - -int sLuaHandle::write(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(), i; - size_t t; - ssize_t r; - Handle * h; - Byte * b; - - if ((n == 2) && L->isstring()) { - return writestring(_L); - } - - if ((n != 3) || !L->isnumber() || !L->istable(2)) { - L->error("Incorrect arguments to method `Headle::write'"); - } - - t = L->tonumber(); - b = (Byte *) malloc(t); - h = (Handle *) LuaObject::getme(L); - - for (i = 0; i < t; i++) { - L->push((lua_Number) i); - L->gettable(2); - b[i] = L->tonumber(); - L->pop(); - } - - r = h->write(b, t); - - free(b); - - L->push((lua_Number) r); - - return 1; -} - -int sLuaHandle::writestring(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(), i; - Handle * h; - String r; - - if ((n != 2) || !L->isstring()) { - L->error("Incorrect arguments to method `Headle::writestring'"); - } - - h = (Handle *) LuaObject::getme(L); - r = L->tostring(); - - (*h) << r; - - return 0; -} - -int sLuaHandle::writeU8(lua_State * L) { - return write(L, U8); -} - -int sLuaHandle::writeU16(lua_State * L) { - return write(L, U16); -} - -int sLuaHandle::writeU32(lua_State * L) { - return write(L, U32); -} - -int sLuaHandle::read(lua_State * _L, int t) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - lua_Number r; - Handle * h; - - if (n != 1) { - L->error("Incorrect arguments to method `Headle::readUx'"); - } - - h = (Handle *) LuaObject::getme(L); - - switch (t) { - case U8: r = h->readU8(); break; - case U16: r = h->readU16(); break; - case U32: r = h->readU32(); break; - } - - L->push(r); - - return 1; -} - -int sLuaHandle::write(lua_State * _L, int t) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - lua_Number r; - Handle * h; - - if ((n != 2) || !L->isnumber()) { - L->error("Incorrect arguments to method `Headle::writeUx'"); - } - - h = (Handle *) LuaObject::getme(L); - r = L->tonumber(); - - switch (t) { - case U8: h->writeU8(r); break; - case U16: h->writeU16(r); break; - case U32: h->writeU32(r); break; - } - - return 0; -} - -int sLuaHandle::copyfrom(lua_State * L) { - return copy(L, from); -} - -int sLuaHandle::copyto(lua_State * L) { - return copy(L, to); -} - -int sLuaHandle::copy(lua_State * _L, int dir) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - lua_Number r; - Handle * s, * d; - - if ((n < 2) || (n > 3) || ((n == 3) && !L->isnumber(3))) { - L->error("Incorrect arguments to function `handlecopy'"); - } - - s = (Handle *) LuaObject::getme(L, 1); - d = (Handle *) LuaObject::getme(L, 2); - - if (n == 3) { - r = L->tonumber(); - } else { - r = -1; - } - - if (dir == from) { - SWAP(s, d); - } - - s->copyto(d, r); - - return 0; -} - -int sLuaHandle::isclosed(lua_State * L) { - return getcaps(L, capisclosed); -} - -int sLuaHandle::isnonblock(lua_State * L) { - return getcaps(L, capisnonblock); -} - -int sLuaHandle::canread(lua_State * L) { - return getcaps(L, capcanread); -} - -int sLuaHandle::canwrite(lua_State * L) { - return getcaps(L, capcanwrite); -} - -int sLuaHandle::canseek(lua_State * L) { - return getcaps(L, capcanseek); -} - -int sLuaHandle::canwatch(lua_State * L) { - return getcaps(L, capcanwatch); -} - -int sLuaHandle::getcaps(lua_State * _L, int cap) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - bool r; - Handle * h; - - if (n != 1) { - L->error("Incorrect arguments to method `Handle::getcaps'"); - } - - h = (Handle *) LuaObject::getme(L); - - switch (cap) { - case capisclosed: r = h->IsClosed(); break; - case capisnonblock: r = h->IsNonBlock(); break; - case capcanread: r = h->CanRead(); break; - case capcanwrite: r = h->CanWrite(); break; - case capcanseek: r = h->CanSeek(); break; - case capcanwatch: r = h->CanWatch(); break; - } - - L->push(r); - - return 1; -} - -int sLuaHandle::setnonblock(lua_State * L) { - return action(L, Asetnonblock); -} - -int sLuaHandle::tell(lua_State * L) { - return action(L, Atell); -} - -int sLuaHandle::getname(lua_State * L) { - return action(L, Agetname); -} - -int sLuaHandle::getsize(lua_State * L) { - return action(L, Agetsize); -} - -int sLuaHandle::getmodif(lua_State * L) { - return action(L, Agetmodif); -} - -int sLuaHandle::close(lua_State * L) { - return action(L, Aclose); -} - -int sLuaHandle::flush(lua_State * L) { - return action(L, Aflush); -} - -int sLuaHandle::action(lua_State * _L, int act) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - int r = 1; - Handle * h; - - if (n != 1) { - L->error("Incorrect arguments to method `Handle::action'"); - } - - h = (Handle *) LuaObject::getme(L); - - switch (act) { - case Asetnonblock: r = 0; h->SetNonBlock(); break; - case Atell: L->push((lua_Number) h->tell()); break; - case Agetname: L->push(h->GetName()); break; - case Agetsize: L->push((lua_Number) h->GetSize()); break; - case Agetmodif: L->push((lua_Number) h->GetModif()); break; - case Aclose: r = 0; h->close(); break; - case Aflush: r = 0; h->Flush(); break; - } - - return r; -} - -int sLuaHandle::setz(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - int z = 9; - Handle * h; - - if ((n < 1) || (n > 2) || ((n == 2) && !L->isnumber(2))) { - L->error("Incorrect arguments to method `Handle::setz'"); - } - - h = (Handle *) LuaObject::getme(L); - - if (n == 2) { - z = L->tonumber(2); - } - - h->SetZ(z); - - return 0; -} - -int sLuaHandle::seek(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - off_t off; - int wheel; - Handle * h; - - if ((n < 2) || (n > 3) || !L->isnumber(2) || ((n == 3) && !L->isnumber(3))) { - L->error("Incorrect arguments to method `Handle::seek'"); - } - - h = (Handle *) LuaObject::getme(L); - - off = L->tonumber(2); - - if (n == 3) { - wheel = L->tonumber(3); - } else { - wheel = SEEK_SET; - } - - L->push((lua_Number) h->seek(off, wheel)); - - return 1; -} - -int sLuaHandle::bindex(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - const Buffer * b; - - if (n != 2) { - L->error("Inconsistant call to metamethod Buffer::index"); - } - - if (!L->isnumber()) { - L->push(); - return 1; - } - - b = (Buffer *) LuaObject::getme(L); - - L->push((lua_Number) (*b)[L->tonumber()]); - - return 1; -} - -int sLuaHandle::bnewindex(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Buffer * b; - - if (n != 3) { - L->error("Inconsistant call to metamethod Buffer::newindex"); - } - - if (!L->isnumber(2)) { - L->settable(1, true); - return 0; - } - - if (!L->isnumber(3)) { - L->error("Can't write a non-number to buffer"); - } - - b = (Buffer *) LuaObject::getme(L); - - (*b)[L->tonumber(2)] = L->tonumber(3); - - return 0; -} - -int sLuaHandle::btell(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - Buffer * h; - - if (n != 1) { - L->error("Incorrect arguments to method `Buffer::wtell'"); - } - - h = (Buffer *) LuaObject::getme(L); - L->push((lua_Number) h->wtell()); - return 1; -} - -int sLuaHandle::bseek(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - off_t off; - int wheel; - Buffer * h; - - if ((n < 2) || (n > 3) || !L->isnumber(2) || ((n == 3) && !L->isnumber(3))) { - L->error("Incorrect arguments to method `Buffer::wseek'"); - } - - h = (Buffer *) LuaObject::getme(L); - - off = L->tonumber(2); - - if (n == 3) { - wheel = L->tonumber(3); - } else { - wheel = SEEK_SET; - } - - L->push((lua_Number) h->wseek(off, wheel)); - - return 1; -} - -int sLuaHandle::exists(lua_State * _L) { - Lua * L = Lua::find(_L); - int n = L->gettop(); - bool r = true; - - if (n != 1) { - L->error("Incorrect number of arguments to function exists"); - } - - try { - Input testing(L->tostring()); - } - catch (IOGeneral & e) { - r = false; - } - - L->push(r); - - return 1; -} - -void LuaInput::pushmembers(Lua * L) { - LuaHandle::pushmembers(L); -} - -void LuaOutput::pushmembers(Lua * L) { - LuaHandle::pushmembers(L); -} - -void LuaBuffer::pushmembers(Lua * L) { - LuaHandle::pushmembers(L); - pushmeta(L, "__index", sLuaHandle::bindex); - pushmeta(L, "__newindex", sLuaHandle::bnewindex); - pushit(L, "wtell", sLuaHandle::btell); - pushit(L, "wseek", sLuaHandle::bseek); -} - -void LuaHandle::pushmembers(Lua * L) { - pushme(L, h); - - pushit(L, "read", &sLuaHandle::read); - pushit(L, "write", &sLuaHandle::write); - - pushit(L, "readU8", sLuaHandle::readU8); - pushit(L, "readU16", sLuaHandle::readU16); - pushit(L, "readU32", sLuaHandle::readU32); - pushit(L, "writeU8", sLuaHandle::writeU8); - pushit(L, "writeU16", sLuaHandle::writeU16); - pushit(L, "writeU32", sLuaHandle::writeU32); - - pushit(L, "copyfrom", sLuaHandle::copyfrom); - pushit(L, "copyto", sLuaHandle::copyto); - L->declarefunc("handlecopy", sLuaHandle::copyfrom); - - pushit(L, "isclosed", sLuaHandle::isclosed); - pushit(L, "isnonblock", sLuaHandle::isnonblock); - pushit(L, "canread", sLuaHandle::canread); - pushit(L, "canwrite", sLuaHandle::canwatch); - pushit(L, "canseek", sLuaHandle::canseek); - pushit(L, "canwatch", sLuaHandle::canwatch); - - pushit(L, "setnonblock", sLuaHandle::setnonblock); - pushit(L, "tell", sLuaHandle::tell); - pushit(L, "getname", sLuaHandle::getname); - pushit(L, "getsize", sLuaHandle::getsize); - pushit(L, "getmodif", sLuaHandle::getmodif); - pushit(L, "close", sLuaHandle::close); - pushit(L, "flush", sLuaHandle::flush); - - pushit(L, "seek", sLuaHandle::seek); - pushit(L, "setz", sLuaHandle::setz); - - L->declarefunc("exists", sLuaHandle::exists); - - L->push("SEEK_SET"); - L->push((lua_Number) SEEK_SET); - L->settable(LUA_GLOBALSINDEX); - - L->push("SEEK_CUR"); - L->push((lua_Number) SEEK_CUR); - L->settable(LUA_GLOBALSINDEX); - - L->push("SEEK_END"); - L->push((lua_Number) SEEK_END); - L->settable(LUA_GLOBALSINDEX); -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: LuaHandle.cc,v 1.14 2004-11-27 21:35:19 pixel Exp $ */
+
+#include "LuaHandle.h"
+
+LuaInput::LuaInput(Input * h) : LuaHandle(h) { }
+LuaOutput::LuaOutput(Output * h) : LuaHandle(h) { }
+LuaBuffer::LuaBuffer(Buffer * h) : LuaHandle(h) { }
+LuaHandle::LuaHandle(Handle * _h) : h(_h) { }
+
+class sLuaHandle : public Base {
+ public:
+ static int newinput(lua_State * L);
+ static int newoutput(lua_State * L);
+ static int newbuffer(lua_State * L);
+ static int read(lua_State * L);
+ static int readstring(lua_State * L);
+ static int readU8(lua_State * L);
+ static int readU16(lua_State * L);
+ static int readU32(lua_State * L);
+ static int write(lua_State * L);
+ static int writestring(lua_State * L);
+ static int writeU8(lua_State * L);
+ static int writeU16(lua_State * L);
+ static int writeU32(lua_State * L);
+ static int copyfrom(lua_State * L);
+ static int copyto(lua_State * L);
+ static int isclosed(lua_State * L);
+ static int isnonblock(lua_State * L);
+ static int canread(lua_State * L);
+ static int canwrite(lua_State * L);
+ static int canseek(lua_State * L);
+ static int canwatch(lua_State * L);
+ static int setnonblock(lua_State * L);
+ static int tell(lua_State * L);
+ static int getname(lua_State * L);
+ static int getsize(lua_State * L);
+ static int getmodif(lua_State * L);
+ static int close(lua_State * L);
+ static int flush(lua_State * L);
+ static int seek(lua_State * L);
+ static int setz(lua_State * L);
+ static int bindex(lua_State * L);
+ static int bnewindex(lua_State * L);
+ static int bseek(lua_State * L);
+ static int btell(lua_State * L);
+ static int exists(lua_State * L);
+ private:
+ static int read(lua_State * L, int);
+ static int write(lua_State * L, int);
+ static int copy(lua_State * L, int);
+ static int getcaps(lua_State * L, int);
+ static int action(lua_State * L, int);
+ enum {
+ U8, U16, U32
+ };
+ enum {
+ from, to
+ };
+ enum {
+ capisclosed, capisnonblock, capcanread, capcanwrite, capcanseek, capcanwatch
+ };
+ enum {
+ Asetnonblock, Atell, Agetname, Agetsize, Agetmodif, Aclose, Aflush
+ };
+};
+
+void LuaInput::pushconstruct(Lua * L) {
+ L->declarefunc("Input", sLuaHandle::newinput);
+}
+
+void LuaOutput::pushconstruct(Lua * L) {
+ L->declarefunc("Output", sLuaHandle::newoutput);
+}
+
+void LuaBuffer::pushconstruct(Lua * L) {
+ L->declarefunc("Buffer", sLuaHandle::newbuffer);
+}
+
+int sLuaHandle::newinput(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+
+ if ((n != 1) || !L->isstring()) {
+ L->error("Incorrect arguments to constructor `Input'");
+ }
+
+ LuaInput i(new Input(L->tostring()));
+ i.pushdestruct(L);
+
+ return 1;
+}
+
+int sLuaHandle::newoutput(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+
+ if ((n != 1) || !L->isstring()) {
+ L->error("Incorrect arguments to constructor `Input'");
+ }
+
+ LuaOutput o(new Output(L->tostring()));
+ o.pushdestruct(L);
+
+ return 1;
+}
+
+int sLuaHandle::newbuffer(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ bool seekable = false;
+
+ if ((n > 1) || ((n == 1) && (!L->isboolean()))) {
+ L->error("Incorrect arguments to constructor `Buffer'");
+ }
+
+ if (n == 1)
+ seekable = L->toboolean();
+
+ LuaBuffer o(new Buffer(seekable));
+ o.pushdestruct(L);
+
+ return 1;
+}
+
+int sLuaHandle::read(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop(), i;
+ size_t t;
+ ssize_t r;
+ Handle * h;
+ Byte * b;
+
+ if (n == 1) {
+ return readstring(_L);
+ }
+
+ if ((n != 2) || !L->isnumber()) {
+ L->error("Incorrect arguments to method `Headle::read'");
+ }
+
+ t = L->tonumber();
+ b = (Byte *) malloc(t);
+ h = (Handle *) LuaObject::getme(L);
+
+ L->newtable();
+
+ r = h->read(b, t);
+
+ for (i = 0; i < r; i++) {
+ L->push((lua_Number) i);
+ L->push((lua_Number) b[i]);
+ L->settable();
+ }
+
+ free(b);
+
+ L->push((lua_Number) r);
+
+ return 2;
+}
+
+int sLuaHandle::readstring(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop(), i;
+ Handle * h;
+ String r;
+
+ if (n != 1) {
+ L->error("Incorrect arguments to method `Headle::readstring'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+
+ (*h) >> r;
+
+ L->push(r);
+
+ return 1;
+}
+
+int sLuaHandle::readU8(lua_State * L) {
+ return read(L, U8);
+}
+
+int sLuaHandle::readU16(lua_State * L) {
+ return read(L, U16);
+}
+
+int sLuaHandle::readU32(lua_State * L) {
+ return read(L, U32);
+}
+
+int sLuaHandle::write(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop(), i;
+ size_t t;
+ ssize_t r;
+ Handle * h;
+ Byte * b;
+
+ if ((n == 2) && L->isstring()) {
+ return writestring(_L);
+ }
+
+ if ((n != 3) || !L->isnumber() || !L->istable(2)) {
+ L->error("Incorrect arguments to method `Headle::write'");
+ }
+
+ t = L->tonumber();
+ b = (Byte *) malloc(t);
+ h = (Handle *) LuaObject::getme(L);
+
+ for (i = 0; i < t; i++) {
+ L->push((lua_Number) i);
+ L->gettable(2);
+ b[i] = L->tonumber();
+ L->pop();
+ }
+
+ r = h->write(b, t);
+
+ free(b);
+
+ L->push((lua_Number) r);
+
+ return 1;
+}
+
+int sLuaHandle::writestring(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop(), i;
+ Handle * h;
+ String r;
+
+ if ((n != 2) || !L->isstring()) {
+ L->error("Incorrect arguments to method `Headle::writestring'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+ r = L->tostring();
+
+ (*h) << r;
+
+ return 0;
+}
+
+int sLuaHandle::writeU8(lua_State * L) {
+ return write(L, U8);
+}
+
+int sLuaHandle::writeU16(lua_State * L) {
+ return write(L, U16);
+}
+
+int sLuaHandle::writeU32(lua_State * L) {
+ return write(L, U32);
+}
+
+int sLuaHandle::read(lua_State * _L, int t) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ lua_Number r;
+ Handle * h;
+
+ if (n != 1) {
+ L->error("Incorrect arguments to method `Headle::readUx'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+
+ switch (t) {
+ case U8: r = h->readU8(); break;
+ case U16: r = h->readU16(); break;
+ case U32: r = h->readU32(); break;
+ }
+
+ L->push(r);
+
+ return 1;
+}
+
+int sLuaHandle::write(lua_State * _L, int t) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ lua_Number r;
+ Handle * h;
+
+ if ((n != 2) || !L->isnumber()) {
+ L->error("Incorrect arguments to method `Headle::writeUx'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+ r = L->tonumber();
+
+ switch (t) {
+ case U8: h->writeU8(r); break;
+ case U16: h->writeU16(r); break;
+ case U32: h->writeU32(r); break;
+ }
+
+ return 0;
+}
+
+int sLuaHandle::copyfrom(lua_State * L) {
+ return copy(L, from);
+}
+
+int sLuaHandle::copyto(lua_State * L) {
+ return copy(L, to);
+}
+
+int sLuaHandle::copy(lua_State * _L, int dir) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ lua_Number r;
+ Handle * s, * d;
+
+ if ((n < 2) || (n > 3) || ((n == 3) && !L->isnumber(3))) {
+ L->error("Incorrect arguments to function `handlecopy'");
+ }
+
+ s = (Handle *) LuaObject::getme(L, 1);
+ d = (Handle *) LuaObject::getme(L, 2);
+
+ if (n == 3) {
+ r = L->tonumber();
+ } else {
+ r = -1;
+ }
+
+ if (dir == from) {
+ SWAP(s, d);
+ }
+
+ s->copyto(d, r);
+
+ return 0;
+}
+
+int sLuaHandle::isclosed(lua_State * L) {
+ return getcaps(L, capisclosed);
+}
+
+int sLuaHandle::isnonblock(lua_State * L) {
+ return getcaps(L, capisnonblock);
+}
+
+int sLuaHandle::canread(lua_State * L) {
+ return getcaps(L, capcanread);
+}
+
+int sLuaHandle::canwrite(lua_State * L) {
+ return getcaps(L, capcanwrite);
+}
+
+int sLuaHandle::canseek(lua_State * L) {
+ return getcaps(L, capcanseek);
+}
+
+int sLuaHandle::canwatch(lua_State * L) {
+ return getcaps(L, capcanwatch);
+}
+
+int sLuaHandle::getcaps(lua_State * _L, int cap) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ bool r;
+ Handle * h;
+
+ if (n != 1) {
+ L->error("Incorrect arguments to method `Handle::getcaps'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+
+ switch (cap) {
+ case capisclosed: r = h->IsClosed(); break;
+ case capisnonblock: r = h->IsNonBlock(); break;
+ case capcanread: r = h->CanRead(); break;
+ case capcanwrite: r = h->CanWrite(); break;
+ case capcanseek: r = h->CanSeek(); break;
+ case capcanwatch: r = h->CanWatch(); break;
+ }
+
+ L->push(r);
+
+ return 1;
+}
+
+int sLuaHandle::setnonblock(lua_State * L) {
+ return action(L, Asetnonblock);
+}
+
+int sLuaHandle::tell(lua_State * L) {
+ return action(L, Atell);
+}
+
+int sLuaHandle::getname(lua_State * L) {
+ return action(L, Agetname);
+}
+
+int sLuaHandle::getsize(lua_State * L) {
+ return action(L, Agetsize);
+}
+
+int sLuaHandle::getmodif(lua_State * L) {
+ return action(L, Agetmodif);
+}
+
+int sLuaHandle::close(lua_State * L) {
+ return action(L, Aclose);
+}
+
+int sLuaHandle::flush(lua_State * L) {
+ return action(L, Aflush);
+}
+
+int sLuaHandle::action(lua_State * _L, int act) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ int r = 1;
+ Handle * h;
+
+ if (n != 1) {
+ L->error("Incorrect arguments to method `Handle::action'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+
+ switch (act) {
+ case Asetnonblock: r = 0; h->SetNonBlock(); break;
+ case Atell: L->push((lua_Number) h->tell()); break;
+ case Agetname: L->push(h->GetName()); break;
+ case Agetsize: L->push((lua_Number) h->GetSize()); break;
+ case Agetmodif: L->push((lua_Number) h->GetModif()); break;
+ case Aclose: r = 0; h->close(); break;
+ case Aflush: r = 0; h->Flush(); break;
+ }
+
+ return r;
+}
+
+int sLuaHandle::setz(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ int z = 9;
+ Handle * h;
+
+ if ((n < 1) || (n > 2) || ((n == 2) && !L->isnumber(2))) {
+ L->error("Incorrect arguments to method `Handle::setz'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+
+ if (n == 2) {
+ z = L->tonumber(2);
+ }
+
+ h->SetZ(z);
+
+ return 0;
+}
+
+int sLuaHandle::seek(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ off_t off;
+ int wheel;
+ Handle * h;
+
+ if ((n < 2) || (n > 3) || !L->isnumber(2) || ((n == 3) && !L->isnumber(3))) {
+ L->error("Incorrect arguments to method `Handle::seek'");
+ }
+
+ h = (Handle *) LuaObject::getme(L);
+
+ off = L->tonumber(2);
+
+ if (n == 3) {
+ wheel = L->tonumber(3);
+ } else {
+ wheel = SEEK_SET;
+ }
+
+ L->push((lua_Number) h->seek(off, wheel));
+
+ return 1;
+}
+
+int sLuaHandle::bindex(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ const Buffer * b;
+
+ if (n != 2) {
+ L->error("Inconsistant call to metamethod Buffer::index");
+ }
+
+ if (!L->isnumber()) {
+ L->push();
+ return 1;
+ }
+
+ b = (Buffer *) LuaObject::getme(L);
+
+ L->push((lua_Number) (*b)[L->tonumber()]);
+
+ return 1;
+}
+
+int sLuaHandle::bnewindex(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ Buffer * b;
+
+ if (n != 3) {
+ L->error("Inconsistant call to metamethod Buffer::newindex");
+ }
+
+ if (!L->isnumber(2)) {
+ L->settable(1, true);
+ return 0;
+ }
+
+ if (!L->isnumber(3)) {
+ L->error("Can't write a non-number to buffer");
+ }
+
+ b = (Buffer *) LuaObject::getme(L);
+
+ (*b)[L->tonumber(2)] = L->tonumber(3);
+
+ return 0;
+}
+
+int sLuaHandle::btell(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ Buffer * h;
+
+ if (n != 1) {
+ L->error("Incorrect arguments to method `Buffer::wtell'");
+ }
+
+ h = (Buffer *) LuaObject::getme(L);
+ L->push((lua_Number) h->wtell());
+ return 1;
+}
+
+int sLuaHandle::bseek(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ off_t off;
+ int wheel;
+ Buffer * h;
+
+ if ((n < 2) || (n > 3) || !L->isnumber(2) || ((n == 3) && !L->isnumber(3))) {
+ L->error("Incorrect arguments to method `Buffer::wseek'");
+ }
+
+ h = (Buffer *) LuaObject::getme(L);
+
+ off = L->tonumber(2);
+
+ if (n == 3) {
+ wheel = L->tonumber(3);
+ } else {
+ wheel = SEEK_SET;
+ }
+
+ L->push((lua_Number) h->wseek(off, wheel));
+
+ return 1;
+}
+
+int sLuaHandle::exists(lua_State * _L) {
+ Lua * L = Lua::find(_L);
+ int n = L->gettop();
+ bool r = true;
+
+ if (n != 1) {
+ L->error("Incorrect number of arguments to function exists");
+ }
+
+ try {
+ Input testing(L->tostring());
+ }
+ catch (IOGeneral & e) {
+ r = false;
+ }
+
+ L->push(r);
+
+ return 1;
+}
+
+void LuaInput::pushmembers(Lua * L) {
+ LuaHandle::pushmembers(L);
+}
+
+void LuaOutput::pushmembers(Lua * L) {
+ LuaHandle::pushmembers(L);
+}
+
+void LuaBuffer::pushmembers(Lua * L) {
+ LuaHandle::pushmembers(L);
+ pushmeta(L, "__index", sLuaHandle::bindex);
+ pushmeta(L, "__newindex", sLuaHandle::bnewindex);
+ pushit(L, "wtell", sLuaHandle::btell);
+ pushit(L, "wseek", sLuaHandle::bseek);
+}
+
+void LuaHandle::pushmembers(Lua * L) {
+ pushme(L, h);
+
+ pushit(L, "read", &sLuaHandle::read);
+ pushit(L, "write", &sLuaHandle::write);
+
+ pushit(L, "readU8", sLuaHandle::readU8);
+ pushit(L, "readU16", sLuaHandle::readU16);
+ pushit(L, "readU32", sLuaHandle::readU32);
+ pushit(L, "writeU8", sLuaHandle::writeU8);
+ pushit(L, "writeU16", sLuaHandle::writeU16);
+ pushit(L, "writeU32", sLuaHandle::writeU32);
+
+ pushit(L, "copyfrom", sLuaHandle::copyfrom);
+ pushit(L, "copyto", sLuaHandle::copyto);
+ L->declarefunc("handlecopy", sLuaHandle::copyfrom);
+
+ pushit(L, "isclosed", sLuaHandle::isclosed);
+ pushit(L, "isnonblock", sLuaHandle::isnonblock);
+ pushit(L, "canread", sLuaHandle::canread);
+ pushit(L, "canwrite", sLuaHandle::canwatch);
+ pushit(L, "canseek", sLuaHandle::canseek);
+ pushit(L, "canwatch", sLuaHandle::canwatch);
+
+ pushit(L, "setnonblock", sLuaHandle::setnonblock);
+ pushit(L, "tell", sLuaHandle::tell);
+ pushit(L, "getname", sLuaHandle::getname);
+ pushit(L, "getsize", sLuaHandle::getsize);
+ pushit(L, "getmodif", sLuaHandle::getmodif);
+ pushit(L, "close", sLuaHandle::close);
+ pushit(L, "flush", sLuaHandle::flush);
+
+ pushit(L, "seek", sLuaHandle::seek);
+ pushit(L, "setz", sLuaHandle::setz);
+
+ L->declarefunc("exists", sLuaHandle::exists);
+
+ L->push("SEEK_SET");
+ L->push((lua_Number) SEEK_SET);
+ L->settable(LUA_GLOBALSINDEX);
+
+ L->push("SEEK_CUR");
+ L->push((lua_Number) SEEK_CUR);
+ L->settable(LUA_GLOBALSINDEX);
+
+ L->push("SEEK_END");
+ L->push((lua_Number) SEEK_END);
+ L->settable(LUA_GLOBALSINDEX);
+}
diff --git a/lib/Main.cc b/lib/Main.cc index c9cb87c..840fbd9 100644 --- a/lib/Main.cc +++ b/lib/Main.cc @@ -1,75 +1,75 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: Main.cc,v 1.10 2004-11-21 14:51:31 pixel Exp $ */ - -#ifdef _WIN32 -#include <windows.h> -#endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Exceptions.h" -#include "Main.h" -#include "generic.h" -//#include "gettext.h" - -Main::Main() : setted(false) {} - -Main::~Main() {} - -void Main::set_args(int a_argc, char ** a_argv, char ** a_enve) { - if (setted) { - return; - } - argc = a_argc; - argv = a_argv; - enve = a_enve; - setted = true; -} - -/* -_open_osfhandle -CreateFileMapping -*/ - -int Main::truemain(Main * Application, int argc, char ** argv, char ** enve) { - int r; - - try { - Application->set_args(argc, argv, enve); - r = Application->startup(); - } - catch (Exit e) { - r = e.GetCode(); - } - catch (GeneralException e) { -#ifdef _WIN32 - MessageBox(0, e.GetMsg(), "Application caused an exception", MB_ICONEXCLAMATION | MB_OK); -#endif - Base::printm(M_ERROR, _("The application caused an exception: %s\n"), e.GetMsg()); - return -1; - } - catch (...) { - Base::printm(M_ERROR, _("The application caused an unknow exception\n")); - return -1; - } - return r; -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: Main.cc,v 1.11 2004-11-27 21:35:19 pixel Exp $ */
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Exceptions.h"
+#include "Main.h"
+#include "generic.h"
+//#include "gettext.h"
+
+Main::Main() : setted(false) {}
+
+Main::~Main() {}
+
+void Main::set_args(int a_argc, char ** a_argv, char ** a_enve) {
+ if (setted) {
+ return;
+ }
+ argc = a_argc;
+ argv = a_argv;
+ enve = a_enve;
+ setted = true;
+}
+
+/*
+_open_osfhandle
+CreateFileMapping
+*/
+
+int Main::truemain(Main * Application, int argc, char ** argv, char ** enve) {
+ int r;
+
+ try {
+ Application->set_args(argc, argv, enve);
+ r = Application->startup();
+ }
+ catch (Exit e) {
+ r = e.GetCode();
+ }
+ catch (GeneralException e) {
+#ifdef _WIN32
+ MessageBox(0, e.GetMsg(), "Application caused an exception", MB_ICONEXCLAMATION | MB_OK);
+#endif
+ Base::printm(M_ERROR, _("The application caused an exception: %s\n"), e.GetMsg());
+ return -1;
+ }
+ catch (...) {
+ Base::printm(M_ERROR, _("The application caused an unknow exception\n"));
+ return -1;
+ }
+ return r;
+}
diff --git a/lib/Makefile.am b/lib/Makefile.am index 4d22c9f..47b3076 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -29,6 +29,7 @@ lua/src/LuaLib/lmathlib.c \ lua/src/LuaLib/loadlib.c \ lua/src/LuaLib/lstrlib.c \ lua/src/LuaLib/ltablib.c \ +lua/src/LuaLib/ldirlib.c \ lua/src/lopcodes.c \ lua/src/lparser.c \ lua/src/lstate.c \ diff --git a/lib/Menu.cc b/lib/Menu.cc index 361189f..ec6f187 100644 --- a/lib/Menu.cc +++ b/lib/Menu.cc @@ -1,35 +1,35 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Menu.h" -#include "HttpServ.h" -#include "CopyJob.h" -#include "Buffer.h" - -Menu::Menu(const String & t, const String & U, String * ts, Action ** as, int nb) : - Action(U), tit(t), lt(ts), la(as), nba(nb) { } - -Task * Menu::Do(Variables * v, Variables *, Handle * h) { - int i, f = 0; - Handle * b = new Buffer(); - Task * t = new CopyJob(b, h, -1, true); - - SendHead(b); - (*b) << "<center><TABLE BORDER=0>" << endnl; - for (i = 0; i < nba; i++) { - (*b) << "<TR BGCOLOR=\"#" << (f ? "dddddd" : "cccccc") << "\"><TD ALIGN=\"center\">" << (i + 1) << "</TD><TD>"; - (*b) << "<A HREF=\"/bin/" << (la[i] ? la[i]->GetURL() : "start") << "\">"; - (*b) << lt[i] << "</A></TD></TR>" << endnl; - f = f ? 0 : 1; - } - (*b) << "</TABLE></center>" << endnl; - SendFoot(b); - - Accessed(); - - return t; -} - -String Menu::GetTitle(void) { - return tit; -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Menu.h"
+#include "HttpServ.h"
+#include "CopyJob.h"
+#include "Buffer.h"
+
+Menu::Menu(const String & t, const String & U, String * ts, Action ** as, int nb) :
+ Action(U), tit(t), lt(ts), la(as), nba(nb) { }
+
+Task * Menu::Do(Variables * v, Variables *, Handle * h) {
+ int i, f = 0;
+ Handle * b = new Buffer();
+ Task * t = new CopyJob(b, h, -1, true);
+
+ SendHead(b);
+ (*b) << "<center><TABLE BORDER=0>" << endnl;
+ for (i = 0; i < nba; i++) {
+ (*b) << "<TR BGCOLOR=\"#" << (f ? "dddddd" : "cccccc") << "\"><TD ALIGN=\"center\">" << (i + 1) << "</TD><TD>";
+ (*b) << "<A HREF=\"/bin/" << (la[i] ? la[i]->GetURL() : "start") << "\">";
+ (*b) << lt[i] << "</A></TD></TR>" << endnl;
+ f = f ? 0 : 1;
+ }
+ (*b) << "</TABLE></center>" << endnl;
+ SendFoot(b);
+
+ Accessed();
+
+ return t;
+}
+
+String Menu::GetTitle(void) {
+ return tit;
+}
diff --git a/lib/Message.cc b/lib/Message.cc index 5cb8859..1a381da 100644 --- a/lib/Message.cc +++ b/lib/Message.cc @@ -1,30 +1,30 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "HttpServ.h" -#include "Message.h" -#include "Buffer.h" -#include "CopyJob.h" - -Message::Message(const String & t, const String & m, const String & U, Action * n) : - Action(U), tit(t), msg(m), Next(n) { } - -Task * Message::Do(Variables * v, Variables *, Handle * h) { - Handle * b = new Buffer(); - Task * t = new CopyJob(b, h, -1, true); - - SendHead(b); - (*b) << msg << "<CENTER><FORM METHOD=\"POST\" ACTION=\"/bin/" << (Next ? Next->GetURL() : "start") << "\">" << endnl << - "<INPUT TYPE=\"SUBMIT\" VALUE=\" Ok \">" << endnl; - v->Dump(b); - (*b) << "</FORM></CENTER>" << endnl; - SendFoot(b); - - Accessed(); - - return t; -} - -String Message::GetTitle(void) { - return tit; -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "HttpServ.h"
+#include "Message.h"
+#include "Buffer.h"
+#include "CopyJob.h"
+
+Message::Message(const String & t, const String & m, const String & U, Action * n) :
+ Action(U), tit(t), msg(m), Next(n) { }
+
+Task * Message::Do(Variables * v, Variables *, Handle * h) {
+ Handle * b = new Buffer();
+ Task * t = new CopyJob(b, h, -1, true);
+
+ SendHead(b);
+ (*b) << msg << "<CENTER><FORM METHOD=\"POST\" ACTION=\"/bin/" << (Next ? Next->GetURL() : "start") << "\">" << endnl <<
+ "<INPUT TYPE=\"SUBMIT\" VALUE=\" Ok \">" << endnl;
+ v->Dump(b);
+ (*b) << "</FORM></CENTER>" << endnl;
+ SendFoot(b);
+
+ Accessed();
+
+ return t;
+}
+
+String Message::GetTitle(void) {
+ return tit;
+}
diff --git a/lib/OutPipe.cc b/lib/OutPipe.cc index c8d979c..943bef0 100644 --- a/lib/OutPipe.cc +++ b/lib/OutPipe.cc @@ -1,41 +1,41 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "OutPipe.h" -#include "Input.h" -#include "gettext.h" - -OutPipe::OutPipe() : Handle(pipe(p, 1)), hooked(0) { } - -OutPipe::~OutPipe() { - if (hooked) { - ::close(0); - dup(Stdin.GetHandle()); - } -} - -OutPipe::OutPipe(const OutPipe & o) : Handle(o), hooked(o.hooked) { - p[0] = dup(o.p[0]); - p[1] = GetHandle(); -} - -void OutPipe::Hook() { - if (!hooked) { - hooked = 1; - ::close(0); - dup(p[0]); - ::close(p[0]); - } -} - -bool OutPipe::CanWrite() { - return true; -} - -bool OutPipe::CanRead() { - return false; -} - -String OutPipe::GetName() { - return (String(_("Output pipe to stdin (")) + (hooked ? "" : _("not ")) + _("hooked)")); -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "OutPipe.h"
+#include "Input.h"
+#include "gettext.h"
+
+OutPipe::OutPipe() : Handle(pipe(p, 1)), hooked(0) { }
+
+OutPipe::~OutPipe() {
+ if (hooked) {
+ ::close(0);
+ dup(Stdin.GetHandle());
+ }
+}
+
+OutPipe::OutPipe(const OutPipe & o) : Handle(o), hooked(o.hooked) {
+ p[0] = dup(o.p[0]);
+ p[1] = GetHandle();
+}
+
+void OutPipe::Hook() {
+ if (!hooked) {
+ hooked = 1;
+ ::close(0);
+ dup(p[0]);
+ ::close(p[0]);
+ }
+}
+
+bool OutPipe::CanWrite() {
+ return true;
+}
+
+bool OutPipe::CanRead() {
+ return false;
+}
+
+String OutPipe::GetName() {
+ return (String(_("Output pipe to stdin (")) + (hooked ? "" : _("not ")) + _("hooked)"));
+}
diff --git a/lib/Output.cc b/lib/Output.cc index ed3e852..8ae02b7 100644 --- a/lib/Output.cc +++ b/lib/Output.cc @@ -1,164 +1,164 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: Output.cc,v 1.20 2003-12-26 23:51:33 pixel Exp $ */ - -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#else -#include <io.h> -#endif -#include <fcntl.h> -#include "Output.h" -#include "Exceptions.h" -#include "gettext.h" - -#ifndef S_ISREG -#define S_ISREG(x) 1 -#endif - -Output::Output(String no, int create, int trunc) throw (GeneralException) : - Handle(no.strlen() ? wrapopen(no.to_charp(), create, trunc) : dup(1)), - n(no) { - if (GetHandle() < 0) { - throw IOGeneral(String(_("Error opening file ")) + no + _(" for writing: ") + strerror(errno)); - } - - size = lseek(GetHandle(), 0, SEEK_END); - lseek(GetHandle(), 0, SEEK_SET); - - struct stat s; - - fstat(GetHandle(), &s); - - date_modif = s.st_mtime; -} - -int Output::wrapopen(const String & n, int create, int trunc) { - hFile = 0; -#ifndef _WIN32 - return open(n.to_charp(), (create ? O_CREAT : 0) | - (trunc ? O_TRUNC : 0) | O_WRONLY, 00666); -#else -#ifdef NO_HFILE - return _creat(n.to_charp(), _S_IREAD | _S_IWRITE); -#else - DWORD dwCreationDisposition; - switch ((create ? 1 : 0) | (trunc ? 2 : 0)) { - case 0: // no creation, no trunc - dwCreationDisposition = OPEN_EXISTING; - break; - case 1: // creation, no trunc if existing - dwCreationDisposition = OPEN_ALWAYS; - break; - case 2: // no creation, trunc of existing file - dwCreationDisposition = TRUNCATE_EXISTING; - break; - case 3: // creation, truc if existing - dwCreationDisposition = CREATE_ALWAYS; - break; - } - hFile = CreateFile( - n.to_charp(), - GENERIC_WRITE, - FILE_SHARE_READ, - 0, - dwCreationDisposition, - FILE_ATTRIBUTE_ARCHIVE, - 0); - return _open_osfhandle((INT_PTR) hFile, O_WRONLY | O_BINARY); -#endif -#endif -} - -Output::Output(const Output & o) : Handle(o), n(o.n) { -} - -bool Output::CanWrite() const { - return 1; -} - -bool Output::CanRead() const { - return 0; -} - -bool Output::CanSeek() const { - struct stat s; - - fstat(GetHandle(), &s); - - return S_ISREG(s.st_mode); -} - -off_t Output::seek(off_t offset, int whence) throw (GeneralException) { - if ((itell = lseek(GetHandle(), offset, whence)) < 0) { - throw IOGeneral(String(_("Error seeking file ")) + n + _(": ") + strerror(errno)); - } -#ifdef PARANOID_SEEK - if (itell != lseek(GetHandle(), 0, SEEK_CUR)) { - throw IOGeneral(String(_("Error seeking file ")) + n + _(": the position does not match")); - } -#endif - return itell; -} - -String Output::GetName() const { - return n; -} - -Stdout_t::Stdout_t() {} - -bool Stdout_t::CanSeek() const { - return 0; -} - -String Stdout_t::GetName() const { - return "Stdout"; -} - -Stderr_t::Stderr_t() : Handle(dup(2)) {} - -bool Stderr_t::CanWrite() const { - return 1; -} - -bool Stderr_t::CanRead() const { - return 0; -} - -bool Stderr_t::CanSeek() const { - return 0; -} - -String Stderr_t::GetName() const { - return "Stderr"; -} - -#ifdef HOOK_STDS -Stdout_t Stdout; -Stderr_t Stderr; -#endif +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: Output.cc,v 1.21 2004-11-27 21:35:19 pixel Exp $ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "Output.h"
+#include "Exceptions.h"
+#include "gettext.h"
+
+#ifndef S_ISREG
+#define S_ISREG(x) 1
+#endif
+
+Output::Output(String no, int create, int trunc) throw (GeneralException) :
+ Handle(no.strlen() ? wrapopen(no.to_charp(), create, trunc) : dup(1)),
+ n(no) {
+ if (GetHandle() < 0) {
+ throw IOGeneral(String(_("Error opening file ")) + no + _(" for writing: ") + strerror(errno));
+ }
+
+ size = lseek(GetHandle(), 0, SEEK_END);
+ lseek(GetHandle(), 0, SEEK_SET);
+
+ struct stat s;
+
+ fstat(GetHandle(), &s);
+
+ date_modif = s.st_mtime;
+}
+
+int Output::wrapopen(const String & n, int create, int trunc) {
+ hFile = 0;
+#ifndef _WIN32
+ return open(n.to_charp(), (create ? O_CREAT : 0) |
+ (trunc ? O_TRUNC : 0) | O_WRONLY, 00666);
+#else
+#ifdef NO_HFILE
+ return _creat(n.to_charp(), _S_IREAD | _S_IWRITE);
+#else
+ DWORD dwCreationDisposition;
+ switch ((create ? 1 : 0) | (trunc ? 2 : 0)) {
+ case 0: // no creation, no trunc
+ dwCreationDisposition = OPEN_EXISTING;
+ break;
+ case 1: // creation, no trunc if existing
+ dwCreationDisposition = OPEN_ALWAYS;
+ break;
+ case 2: // no creation, trunc of existing file
+ dwCreationDisposition = TRUNCATE_EXISTING;
+ break;
+ case 3: // creation, truc if existing
+ dwCreationDisposition = CREATE_ALWAYS;
+ break;
+ }
+ hFile = CreateFile(
+ n.to_charp(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ 0,
+ dwCreationDisposition,
+ FILE_ATTRIBUTE_ARCHIVE,
+ 0);
+ return _open_osfhandle((INT_PTR) hFile, O_WRONLY | O_BINARY);
+#endif
+#endif
+}
+
+Output::Output(const Output & o) : Handle(o), n(o.n) {
+}
+
+bool Output::CanWrite() const {
+ return 1;
+}
+
+bool Output::CanRead() const {
+ return 0;
+}
+
+bool Output::CanSeek() const {
+ struct stat s;
+
+ fstat(GetHandle(), &s);
+
+ return S_ISREG(s.st_mode);
+}
+
+off_t Output::seek(off_t offset, int whence) throw (GeneralException) {
+ if ((itell = lseek(GetHandle(), offset, whence)) < 0) {
+ throw IOGeneral(String(_("Error seeking file ")) + n + _(": ") + strerror(errno));
+ }
+#ifdef PARANOID_SEEK
+ if (itell != lseek(GetHandle(), 0, SEEK_CUR)) {
+ throw IOGeneral(String(_("Error seeking file ")) + n + _(": the position does not match"));
+ }
+#endif
+ return itell;
+}
+
+String Output::GetName() const {
+ return n;
+}
+
+Stdout_t::Stdout_t() {}
+
+bool Stdout_t::CanSeek() const {
+ return 0;
+}
+
+String Stdout_t::GetName() const {
+ return "Stdout";
+}
+
+Stderr_t::Stderr_t() : Handle(dup(2)) {}
+
+bool Stderr_t::CanWrite() const {
+ return 1;
+}
+
+bool Stderr_t::CanRead() const {
+ return 0;
+}
+
+bool Stderr_t::CanSeek() const {
+ return 0;
+}
+
+String Stderr_t::GetName() const {
+ return "Stderr";
+}
+
+#ifdef HOOK_STDS
+Stdout_t Stdout;
+Stderr_t Stderr;
+#endif
diff --git a/lib/ReadJob.cc b/lib/ReadJob.cc index c31b894..63557c2 100644 --- a/lib/ReadJob.cc +++ b/lib/ReadJob.cc @@ -1,52 +1,52 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "ReadJob.h" -#include "HttpServ.h" -#include "Regex.h" -#include "gettext.h" - -ReadJob::ReadJob(Handle * as, Handle * ad, const Regex & aregex) : s(as), d(ad), regex(&aregex) { - s->SetNonBlock(); - d->SetNonBlock(); - WaitFor(s, W4_READING); -} - -ReadJob::~ReadJob() { } - -int ReadJob::Do() throw (GeneralException) { - String buff; - - switch (current) { - case 0: - try { - *s >> buff; - } - catch (IOAgain e) { - WaitFor(s, W4_READING); - Suspend(TASK_ON_HOLD); - } - case 1: - try { - *d << buff << endnl; - } - catch (IOAgain e) { - current = 1; - WaitFor(d, W4_WRITING); - Suspend(TASK_ON_HOLD); - } - current = 0; - if (regex->Match(buff)) return TASK_DONE; - } - - if (!s->IsClosed()) { - WaitFor(s, W4_READING); - Suspend(TASK_ON_HOLD); - } - - return TASK_DONE; -} - -String ReadJob::GetName() { - return (String(_("ReadJob from ")) + s->GetName() + _(" to ") + d->GetName()); -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ReadJob.h"
+#include "HttpServ.h"
+#include "Regex.h"
+#include "gettext.h"
+
+ReadJob::ReadJob(Handle * as, Handle * ad, const Regex & aregex) : s(as), d(ad), regex(&aregex) {
+ s->SetNonBlock();
+ d->SetNonBlock();
+ WaitFor(s, W4_READING);
+}
+
+ReadJob::~ReadJob() { }
+
+int ReadJob::Do() throw (GeneralException) {
+ String buff;
+
+ switch (current) {
+ case 0:
+ try {
+ *s >> buff;
+ }
+ catch (IOAgain e) {
+ WaitFor(s, W4_READING);
+ Suspend(TASK_ON_HOLD);
+ }
+ case 1:
+ try {
+ *d << buff << endnl;
+ }
+ catch (IOAgain e) {
+ current = 1;
+ WaitFor(d, W4_WRITING);
+ Suspend(TASK_ON_HOLD);
+ }
+ current = 0;
+ if (regex->Match(buff)) return TASK_DONE;
+ }
+
+ if (!s->IsClosed()) {
+ WaitFor(s, W4_READING);
+ Suspend(TASK_ON_HOLD);
+ }
+
+ return TASK_DONE;
+}
+
+String ReadJob::GetName() {
+ return (String(_("ReadJob from ")) + s->GetName() + _(" to ") + d->GetName());
+}
diff --git a/lib/Regex.cc b/lib/Regex.cc index 258d378..2a86db8 100644 --- a/lib/Regex.cc +++ b/lib/Regex.cc @@ -1,44 +1,44 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Regex.h" -#include "gettext.h" - -char t[1024]; - -Regex empty("^$"), any(".*"); - -Regex::Regex(const String & regex, int acflags, int aeflags) throw (GeneralException) : cflags(acflags), eflags(aeflags), pattern(regex.strdup()) { - int r; - - if ((r = regcomp(&preg, pattern, cflags | REG_NOSUB))) { - std::cerr << _("Error in regcomp:"); - regerror(r, &preg, t, sizeof(t)); - std::cerr << t << std::endl; - throw GeneralException(String(_("Regex \"")) + regex + _("\" failed to compile: ") + t + "\n"); - } -} - -Regex::Regex(const Regex & regex) : pattern(Base::strdup(pattern)) { - int r; - - if ((r = regcomp(&preg, pattern, cflags | REG_NOSUB))) { - printm(M_ERROR, _("Error in regcomp:")); - regerror(r, &preg, t, sizeof(t)); - printm(M_ERROR, "%s\n", t); - throw GeneralException(String(_("Regex \"")) + pattern + _("\" failed to compile: ") + t + "\n"); - } -} - -Regex::~Regex() { - regfree(&preg); - free(pattern); -} - -bool Regex::Match(const String & s) const { - if (regexec(&preg, s.to_charp(), 0, 0, eflags)) { - return false; - } else { - return true; - } -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Regex.h"
+#include "gettext.h"
+
+char t[1024];
+
+Regex empty("^$"), any(".*");
+
+Regex::Regex(const String & regex, int acflags, int aeflags) throw (GeneralException) : cflags(acflags), eflags(aeflags), pattern(regex.strdup()) {
+ int r;
+
+ if ((r = regcomp(&preg, pattern, cflags | REG_NOSUB))) {
+ std::cerr << _("Error in regcomp:");
+ regerror(r, &preg, t, sizeof(t));
+ std::cerr << t << std::endl;
+ throw GeneralException(String(_("Regex \"")) + regex + _("\" failed to compile: ") + t + "\n");
+ }
+}
+
+Regex::Regex(const Regex & regex) : pattern(Base::strdup(pattern)) {
+ int r;
+
+ if ((r = regcomp(&preg, pattern, cflags | REG_NOSUB))) {
+ printm(M_ERROR, _("Error in regcomp:"));
+ regerror(r, &preg, t, sizeof(t));
+ printm(M_ERROR, "%s\n", t);
+ throw GeneralException(String(_("Regex \"")) + pattern + _("\" failed to compile: ") + t + "\n");
+ }
+}
+
+Regex::~Regex() {
+ regfree(&preg);
+ free(pattern);
+}
+
+bool Regex::Match(const String & s) const {
+ if (regexec(&preg, s.to_charp(), 0, 0, eflags)) {
+ return false;
+ } else {
+ return true;
+ }
+}
@@ -1,76 +1,76 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_MYSQL - -#include "SQL.h" - -SQLConnection::SQLConnection(String host, String user, String passwd, - String db, int port, String socket, - unsigned long cflags) throw (GeneralException) : res(0) { - mysql_init(&con); - - const char * phost = ((ugly_string) host).p; - const char * puser = ((ugly_string) user).p; - const char * ppasswd = ((ugly_string) passwd).p; - const char * pdb = ((ugly_string) db).p; - const char * psocket = ((ugly_string) socket).p; - - phost = *phost ? phost : 0; - psocket = *psocket ? psocket : 0; - - if (!mysql_real_connect(&con, phost, puser, ppasswd, pdb, port, psocket, cflags)) { - throw GeneralException("Could not connect to MySQL host " + host); - } -} - -SQLConnection::~SQLConnection() { - mysql_close(&con); -} - -void SQLConnection::query(String q) throw(GeneralException) { - if (res) { - mysql_free_result(res); - } - - if (mysql_real_query(&con, ((ugly_string)q).p, q.strlen())) { - throw GeneralException(String("Couldn't run query ") + q); - } - - res = mysql_store_result(&con); - - if (res) { - nr = mysql_num_rows(res); - nf = mysql_num_fields(res); - fields = mysql_fetch_fields(res); - } else { - nr = 0; - nf = 0; - fields = 0; - } -} - -int SQLConnection::numrows() { - return nr; -} - -int SQLConnection::numfields() { - return nf; -} - -AssocArray SQLConnection::fetchrow() { - AssocArray r; - MYSQL_ROW row; - int i; - - row = mysql_fetch_row(res); - - for (i = 0; i < nf; i++) { - r[fields[i].name] = row[i]; - } - - return r; -} - -#endif +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_MYSQL
+
+#include "SQL.h"
+
+SQLConnection::SQLConnection(String host, String user, String passwd,
+ String db, int port, String socket,
+ unsigned long cflags) throw (GeneralException) : res(0) {
+ mysql_init(&con);
+
+ const char * phost = ((ugly_string) host).p;
+ const char * puser = ((ugly_string) user).p;
+ const char * ppasswd = ((ugly_string) passwd).p;
+ const char * pdb = ((ugly_string) db).p;
+ const char * psocket = ((ugly_string) socket).p;
+
+ phost = *phost ? phost : 0;
+ psocket = *psocket ? psocket : 0;
+
+ if (!mysql_real_connect(&con, phost, puser, ppasswd, pdb, port, psocket, cflags)) {
+ throw GeneralException("Could not connect to MySQL host " + host);
+ }
+}
+
+SQLConnection::~SQLConnection() {
+ mysql_close(&con);
+}
+
+void SQLConnection::query(String q) throw(GeneralException) {
+ if (res) {
+ mysql_free_result(res);
+ }
+
+ if (mysql_real_query(&con, ((ugly_string)q).p, q.strlen())) {
+ throw GeneralException(String("Couldn't run query ") + q);
+ }
+
+ res = mysql_store_result(&con);
+
+ if (res) {
+ nr = mysql_num_rows(res);
+ nf = mysql_num_fields(res);
+ fields = mysql_fetch_fields(res);
+ } else {
+ nr = 0;
+ nf = 0;
+ fields = 0;
+ }
+}
+
+int SQLConnection::numrows() {
+ return nr;
+}
+
+int SQLConnection::numfields() {
+ return nf;
+}
+
+AssocArray SQLConnection::fetchrow() {
+ AssocArray r;
+ MYSQL_ROW row;
+ int i;
+
+ row = mysql_fetch_row(res);
+
+ for (i = 0; i < nf; i++) {
+ r[fields[i].name] = row[i];
+ }
+
+ return r;
+}
+
+#endif
diff --git a/lib/Socket.cc b/lib/Socket.cc index f3e28df..86b229f 100644 --- a/lib/Socket.cc +++ b/lib/Socket.cc @@ -1,163 +1,163 @@ -#define _BSD_SOCKLEN_T_ int -#include <netdb.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <errno.h> -#include <string.h> -#include <strings.h> -#include <errno.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "BString.h" -#include "Socket.h" -#include "Exceptions.h" -#include "Input.h" -#include "Output.h" -#include "gettext.h" - -Socket::Socket() throw (GeneralException) : Handle(socket(AF_INET, SOCK_STREAM, 0)), connected(false), listening(false), writeclosed(false), readclosed(false) { -// cerr << "Socket(): connected = " << connected << "; readclosed = " << readclosed << "; writeclosed = " << writeclosed << endl; - if (GetHandle() < 0) { - throw GeneralException(_("Error creating socket.")); - } -} - -Socket::Socket(const Socket & s) : Handle(s), connected(s.connected), listening(s.listening), writeclosed(s.writeclosed), readclosed(s.readclosed) { -// cerr << "Constructing a socket by copy...\n"; -// cerr << "Socket(const Socket &): connected = " << connected << "; readclosed = " << readclosed << "; writeclosed = " << writeclosed << endl; -} - -Socket::Socket(int h) : Handle(h), connected(true), listening(false), writeclosed(false), readclosed(false) { } - -String Socket::GetName(void) { - return String("socket"); -} - -bool Socket::IsConnected(void) { - return connected; -} - -bool Socket::IsListening(void) { - return listening; -} - -bool Socket::CanRead(void) { -// cerr << "CanRead: connected = " << connected << "; readclosed = " << readclosed << endl; - return connected && !readclosed; -} - -bool Socket::CanWrite(void) { -// cerr << "CanWrite: connected = " << connected << "; writeclosed = " << writeclosed << endl; - return connected && !writeclosed; -} - -void Socket::CloseWrite(void) { - if (!writeclosed) { - writeclosed = true; - shutdown(GetHandle(), 1); - } -} - -void Socket::CloseRead(void) { - if (!readclosed) { - readclosed = true; - shutdown(GetHandle(), 0); - } -} - - /***********************************************\ - * Toute la suite n'est pas à décrire. Consulter * - * plutôt un document décrivant les sockets. * - \***********************************************/ - - -bool Socket::SetLocal(const String & vhost, int port) { - struct hostent * localhostent; - struct in_addr localhostaddr; - struct sockaddr_in localsocketaddr; - - - memset((void *)&localhostaddr, 0, sizeof(localhostaddr)); - - if (vhost.strlen() != 0) { - if ((localhostent = gethostbyname(vhost.to_charp()))) { - memcpy((void *)&localhostaddr, localhostent->h_addr, sizeof(localhostaddr)); - } else { - return false; - } - } else { - localhostaddr.s_addr = htonl(INADDR_ANY); - } - - memset(&localsocketaddr, 0, sizeof(struct sockaddr_in)); - localsocketaddr.sin_family = AF_INET; - localsocketaddr.sin_addr = localhostaddr; - localsocketaddr.sin_port = htons(port); - - if (bind(GetHandle(), (struct sockaddr *) &localsocketaddr, sizeof(localsocketaddr)) < 0) { - return false; - } else { - return true; - } -} - -bool Socket::Connect(const String & host, int port) { - struct hostent * remotehostent; - struct sockaddr_in remotesocketaddr; - - if (!listening && !connected) { -// cerr << " - Resolving '" << host << "'..." << endl; - if (!(remotehostent = gethostbyname(host.to_charp()))) { - return false; - } - - remotesocketaddr.sin_family = AF_INET; - remotesocketaddr.sin_port = htons(port); - bcopy(remotehostent->h_addr, &remotesocketaddr.sin_addr, remotehostent->h_length); -// cerr << " - Connecting to port " << port << " ..." << endl; - if (!connect(GetHandle(), (struct sockaddr *)&remotesocketaddr, sizeof(remotesocketaddr))) { -// cerr << " - Connected." << endl; - connected = true; - } else { -// cerr << " - Error connecting: " << strerror(errno) << endl; - } - } - return connected; -} - -bool Socket::Listen(void) { - if (!listening && !connected) { - if (!listen(GetHandle(), 10)) { - listening = true; - } - } - return listening; -} - -Socket Socket::Accept(void) throw (GeneralException) { - struct sockaddr inaddr; - socklen_t inlen = sizeof(inaddr); - int h; - - if ((h = accept(GetHandle(), &inaddr, &inlen)) < 0) { - throw GeneralException(_("Failed accepting.")); - } else { - return Socket(h); - } -} - -int Socket::GetPort() { - int r; - struct sockaddr_in localsocketaddr; - socklen_t locallen = sizeof(localsocketaddr); - - if (getsockname(GetHandle(), (struct sockaddr *) &localsocketaddr, &locallen)) { - return -1; - } - - r = ntohs(localsocketaddr.sin_port); - - return r; -} +#define _BSD_SOCKLEN_T_ int
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "BString.h"
+#include "Socket.h"
+#include "Exceptions.h"
+#include "Input.h"
+#include "Output.h"
+#include "gettext.h"
+
+Socket::Socket() throw (GeneralException) : Handle(socket(AF_INET, SOCK_STREAM, 0)), connected(false), listening(false), writeclosed(false), readclosed(false) {
+// cerr << "Socket(): connected = " << connected << "; readclosed = " << readclosed << "; writeclosed = " << writeclosed << endl;
+ if (GetHandle() < 0) {
+ throw GeneralException(_("Error creating socket."));
+ }
+}
+
+Socket::Socket(const Socket & s) : Handle(s), connected(s.connected), listening(s.listening), writeclosed(s.writeclosed), readclosed(s.readclosed) {
+// cerr << "Constructing a socket by copy...\n";
+// cerr << "Socket(const Socket &): connected = " << connected << "; readclosed = " << readclosed << "; writeclosed = " << writeclosed << endl;
+}
+
+Socket::Socket(int h) : Handle(h), connected(true), listening(false), writeclosed(false), readclosed(false) { }
+
+String Socket::GetName(void) {
+ return String("socket");
+}
+
+bool Socket::IsConnected(void) {
+ return connected;
+}
+
+bool Socket::IsListening(void) {
+ return listening;
+}
+
+bool Socket::CanRead(void) {
+// cerr << "CanRead: connected = " << connected << "; readclosed = " << readclosed << endl;
+ return connected && !readclosed;
+}
+
+bool Socket::CanWrite(void) {
+// cerr << "CanWrite: connected = " << connected << "; writeclosed = " << writeclosed << endl;
+ return connected && !writeclosed;
+}
+
+void Socket::CloseWrite(void) {
+ if (!writeclosed) {
+ writeclosed = true;
+ shutdown(GetHandle(), 1);
+ }
+}
+
+void Socket::CloseRead(void) {
+ if (!readclosed) {
+ readclosed = true;
+ shutdown(GetHandle(), 0);
+ }
+}
+
+ /***********************************************\
+ * Toute la suite n'est pas à décrire. Consulter *
+ * plutôt un document décrivant les sockets. *
+ \***********************************************/
+
+
+bool Socket::SetLocal(const String & vhost, int port) {
+ struct hostent * localhostent;
+ struct in_addr localhostaddr;
+ struct sockaddr_in localsocketaddr;
+
+
+ memset((void *)&localhostaddr, 0, sizeof(localhostaddr));
+
+ if (vhost.strlen() != 0) {
+ if ((localhostent = gethostbyname(vhost.to_charp()))) {
+ memcpy((void *)&localhostaddr, localhostent->h_addr, sizeof(localhostaddr));
+ } else {
+ return false;
+ }
+ } else {
+ localhostaddr.s_addr = htonl(INADDR_ANY);
+ }
+
+ memset(&localsocketaddr, 0, sizeof(struct sockaddr_in));
+ localsocketaddr.sin_family = AF_INET;
+ localsocketaddr.sin_addr = localhostaddr;
+ localsocketaddr.sin_port = htons(port);
+
+ if (bind(GetHandle(), (struct sockaddr *) &localsocketaddr, sizeof(localsocketaddr)) < 0) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool Socket::Connect(const String & host, int port) {
+ struct hostent * remotehostent;
+ struct sockaddr_in remotesocketaddr;
+
+ if (!listening && !connected) {
+// cerr << " - Resolving '" << host << "'..." << endl;
+ if (!(remotehostent = gethostbyname(host.to_charp()))) {
+ return false;
+ }
+
+ remotesocketaddr.sin_family = AF_INET;
+ remotesocketaddr.sin_port = htons(port);
+ bcopy(remotehostent->h_addr, &remotesocketaddr.sin_addr, remotehostent->h_length);
+// cerr << " - Connecting to port " << port << " ..." << endl;
+ if (!connect(GetHandle(), (struct sockaddr *)&remotesocketaddr, sizeof(remotesocketaddr))) {
+// cerr << " - Connected." << endl;
+ connected = true;
+ } else {
+// cerr << " - Error connecting: " << strerror(errno) << endl;
+ }
+ }
+ return connected;
+}
+
+bool Socket::Listen(void) {
+ if (!listening && !connected) {
+ if (!listen(GetHandle(), 10)) {
+ listening = true;
+ }
+ }
+ return listening;
+}
+
+Socket Socket::Accept(void) throw (GeneralException) {
+ struct sockaddr inaddr;
+ socklen_t inlen = sizeof(inaddr);
+ int h;
+
+ if ((h = accept(GetHandle(), &inaddr, &inlen)) < 0) {
+ throw GeneralException(_("Failed accepting."));
+ } else {
+ return Socket(h);
+ }
+}
+
+int Socket::GetPort() {
+ int r;
+ struct sockaddr_in localsocketaddr;
+ socklen_t locallen = sizeof(localsocketaddr);
+
+ if (getsockname(GetHandle(), (struct sockaddr *) &localsocketaddr, &locallen)) {
+ return -1;
+ }
+
+ r = ntohs(localsocketaddr.sin_port);
+
+ return r;
+}
diff --git a/lib/String.cc b/lib/String.cc index b2c3dbe..c833134 100644 --- a/lib/String.cc +++ b/lib/String.cc @@ -1,558 +1,558 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: String.cc,v 1.34 2004-07-23 16:56:03 pixel Exp $ */ - -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <ctype.h> -#include <iostream> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef HAVE_GMP -#include <gmpxx.h> -#endif -#include "BString.h" -#include "Exceptions.h" -#include "gettext.h" - -char ** gruikptr; - -extern "C" { - double dateCalc(char *, char *); - int isDateArgument(char *); -} - -char String::t[BUFSIZ + 1]; - -String::String(const String & s) : str(Base::strdup(s.str)), siz(s.siz) { -#ifdef DEBUG - fprintf(stderr, _("Duplicating string `%s', from %p to %p, from this %p to this %p\n"), str, s.str, str, &s, this); -#endif -} - -#ifndef asprintf -extern "C" int asprintf(char **, const char *, ...); -#endif - -String::String(char c) : siz(1) { -#ifdef DEBUG - fprintf(stderr, _("Creating a string with `%c' at %p, this = %p\n"), c, str, this); -#endif -#ifndef HAVE_ASPRINTF - char * t = (char *) malloc(2); - sprintf(t, "%c", c); - str = t; -#else - asprintf(&str, "%c", c); -#endif -} - -String::String(const char * s) : str(Base::strdup(s)), siz(::strlen(str)) { -#ifdef DEBUG - fprintf(stderr, _("Creating a string with `%s' at %p from %p, this = %p\n"), str, str, s, this); -#endif -} - -String::String(int hs, char * s) : str(s), siz(hs) { -#ifdef DEBUG - fprintf(stderr, _("Fast-Creating a string with `%s' at %p from %p, this = %p\n"), str, str, s, this); -#endif -} - -String::String(int i) { -#ifndef HAVE_ASPRINTF - char t[20]; - sprintf(t, "%i", i); - str = Base::strdup(t); -#else - asprintf(&str, "%i", i); -#endif - siz = ::strlen(str); -} - -String::String(unsigned int i) { -#ifndef HAVE_ASPRINTF - char t[20]; - sprintf(t, "%u", i); - str = Base::strdup(t); -#else - asprintf(&str, "%u", i); -#endif - siz = ::strlen(str); -} - -String::String(int64 l) { -#ifndef HAVE_ASPRINTF - char t[40]; - sprintf(t, "%lld", l); - str = Base::strdup(t); -#else - asprintf(&str, "%lld", l); -#endif - siz = ::strlen(str); -} - -String::String(Uint64 l) { -#ifndef HAVE_ASPRINTF - char t[40]; - sprintf(t, "%llu", l); - str = Base::strdup(t); -#else - asprintf(&str, "%llu", l); -#endif - siz = ::strlen(str); -} - -String::String(double d) { -#ifndef HAVE_ASPRINTF - char t[30]; - sprintf(t, "%g", d); - str = Base::strdup(t); -#else - asprintf(&str, "%g", d); -#endif - siz = ::strlen(str); -} - -String::~String() { -#ifdef DEBUG - fprintf(stderr, _("Destroying string @ %p, freeing %p.\n"), this, str); -#endif - free(str); -} - -const char * String::set(const char * s, va_list ap) { - const char * r; - free(str); - if (!s) { - str = Base::strdup(""); - return str; - } - -#ifdef HAVE_GMP - gmp_vasprintf(&str, s, ap); - r = str; -#else // !HAVE_GMP -#ifdef HAVE_VASPRINTF - vasprintf(&str, s, ap); - r = str; -#else // !HAVE_VASPRINTF -#ifdef HAVE_VSNPRINTF - LOCK; - vsnprintf(t, BUFSIZ, s, ap); - str = Base::strdup(r = t); - UNLOCK; -#else // !HAVE_VSNPRINTF -#ifdef _WIN32 -#ifdef _MSC_VER - r = str = (char *) malloc(_vscprintf(s, ap) + 1); - vsprintf(str, s, ap); -#else - LOCK; - _vsnprintf(t, BUFSIZ, s, ap); - str = Base::strdup(r = t); - UNLOCK; -#endif -#else - LOCK; - vsprintf(t, s, ap); - str = Base::strdup(r = t); - UNLOCK; -#endif -#endif // HAVE_VSNPRINTF -#endif // HAVE_VASPRINTF -#endif // HAVE_GMP - siz = ::strlen(str); - return r; -} - -const char * String::set(const char * s, ...) { - const char * r; - va_list ap; - va_start(ap, s); - r = set(s, ap); - va_end(ap); - return r; -} - -const char * String::set(const ugly_string & s, ...) { - const char * r; - va_list ap; - va_start(ap, s); - r = set(s.p, ap); - va_end(ap); - return r; -} - -#ifdef HAVE_VSSCANF -int String::scanf(const char * s, ...) const { - va_list ap; - int t; - - va_start(ap, s); -#ifdef HAVE_GMP - t = gmp_vsscanf(str, s, ap); -#else - t = vsscanf(str, s, ap); -#endif - va_end(ap); - return t; -} - -int String::scanf(const ugly_string & s, ...) const { - va_list ap; - int t; - - va_start(ap, s); -#ifdef HAVE_GMP - t = gmp_vsscanf(str, s.p, ap); -#else - t = vsscanf(str, s.p, ap); -#endif - va_end(ap); - return t; -} -#endif - -const char * String::to_charp(size_t from, ssize_t to) const { - if (to < 0) { - if (from) - strncpy(t, &(str[from]), BUFSIZ); - else - return str; - } else { - if (((size_t) to) >= siz) { - to = siz - 1; - } - - if ((((size_t) to) - from) > BUFSIZ) { - from -= (to - from) - BUFSIZ; - } - - if (((size_t) to) >= from) { - size_t i; - for (i = 0; i <= ((size_t) to) - from; i++) { - t[i] = str[i + from]; - } - t[i] = '\0'; - } else { - t[0] = '\0'; - } - } - return t; -} - -String String::extract(size_t from, ssize_t to) const { - return String(to_charp(from, to)); -} - -char * String::strdup(size_t from, ssize_t to) const { - char * r; - - LOCK; - r = Base::strdup(to_charp(from, to)); - UNLOCK; - - return r; -} - -int String::to_int(void) const { - int r; - - sscanf(str, "%i", &r); - return r; -} - -double String::to_double(void) const { - double r; - - sscanf(str, "%lf", &r); - return r; -} - -String & String::operator=(const String & s) { - if (str != s.str) { - // On évite l'autodestruction... - free(str); - str = s.strdup(); - siz = s.siz; - } - return *this; -} - -String String::operator+(const String & s) const { - char * t = (char *) malloc(s.siz + siz + 1), * u; - - strcpy((u = t), str); - u += siz; - strcpy(u, s.str); - return String(siz + s.siz, t); -} - -String & String::operator+=(const String & s) { - char * t = (char *) malloc(s.siz + siz + 1), * u; - - strcpy((u = t), str); - u += siz; - strcat(u, s.str); - free(str); - str = t; - siz += s.siz; - return (*this); -} - -std::ostream & operator<<(std::ostream & os, const String & s) { - return (os << s.to_charp()); -} - -std::istream & operator>>(std::istream & is, String & s) { - char c = 0; - - s.set(""); - - while (!is.eof()) { - c = is.get(); - if (c == '\n') return is; - if (c == '\r') continue; - s += c; - } - - return is; -} - -bool String::operator!=(const String & s) const { - return (strcmp(str, s.str) != 0); -} - -bool String::operator==(const String & s) const { - return (strcmp(str, s.str) == 0); -} - -bool String::operator<=(const String & s) const { - return (strcmp(str, s.str) <= 0); -} - -bool String::operator>=(const String & s) const { - return (strcmp(str, s.str) >= 0); -} - -bool String::operator<(const String & s) const { - return (strcmp(str, s.str) < 0); -} - -bool String::operator>(const String & s) const { - return (strcmp(str, s.str) > 0); -} - -size_t String::strlen() const { - return (siz); -} - -char String::operator[](size_t i) const { - if (i >= siz) { - return 0; - } else { - return str[i]; - } -} - -char & String::operator[](size_t i) { - static char zero = 0; - - if (i >= siz) { - return zero; - } else { - return str[i]; - } -} - -ssize_t String::strchr(char c, size_t from) const { - for (size_t i = from; i < siz; i++) { - if (str[i] == c) return i; - } - - return -1; -} - -ssize_t String::strrchr(char c) const { - for (size_t i = siz - 1; i >= 0; i--) { - if (str[i] == c) return i; - } - - return -1; -} - -ssize_t String::strstr(const String & s) const { - char * p = ::strstr(str, s.str); - - if (p) { - return p - str; - } else { - return -1; - } -} - -int String::strchrcnt(char c) const { - size_t i, cnt = 0; - for (i = 0; i < siz; i++) { - if (str[i] == c) cnt++; - } - - return cnt; -} - -String String::to_sqldate(void) const { -/* DD/MM/YYYY ==> YYYYMMMDD */ - return (is_date() ? extract(6, 9) + extract(3, 4) + extract(0, 1) : ""); -} - -String String::to_sqltime(void) const { -/* h:m ==> h * 60 + m */ - int p = strchr(':'); - return (is_time() ? String(extract(0, p - 1).to_int() * 60 + extract(p + 1).to_int()) : ""); -} - -String String::from_sqldate(void) const { -/* YYYYMMDD ==> DD/MM/YYYY */ - return ((strlen() == 8) && is_number() ? extract(6, 7) + '/' + extract(4, 5) + '/' + extract(0, 3) : ""); -} - -String String::from_sqltime(void) const { -/* t ==> (t / 60):(t % 60) */ - int t = to_int(); - return (is_number() ? String((int) (t / 60)) + ':' + (t % 60) : ""); -} - -bool String::is_date(void) const { -/* 'DD/MM/YYYY' - 0123456789 */ - - if (strlen() != 10) return false; - if ((str[2] != '/') || (str[5] != '/') || - (!extract(0, 1).is_number()) || - (!extract(3, 4).is_number()) || - (!extract(6, 9).is_number())) { - return (isDateArgument(to_sqldate().str) != 0); - } - - return true; -} - -double String::datedif(const String & s) const { - double r; - if (is_date() && s.is_date()) { - r = dateCalc(str, s.str); - return r < 0 ? -r : r; - } - - return -1; -} - -bool String::is_number(void) const { - for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) { - if ((str[i] > '9') || (str[i] < '0')) return false; - } - return true; -} - -bool String::is_float(void) const { - bool seendot = false; - - for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) { - if ((str[i] > '9') || (str[i] < '0')) { - if ((str[i] == '.') && !seendot) { - seendot = true; - } else { - return false; - } - } - } - - return true; -} - -bool String::is_time(void) const { - int p = strchr(':'); - - if (p == -1) return false; - - // On accepte les heures sous le format xxxxxx:yy pour pouvoir indiquer des durées. - - if ((!extract(0, p - 1).is_number()) || (!extract(p + 1).is_number())) - return false; - - return (extract(p + 1).to_int() < 60) ? true : false; -} - -String operator+(const char * a, const String & b) { - return String(a) + b; -} - -String::operator ugly_string() const { - ugly_string r; - r.p = str; - return r; -} - -String & String::toupper() { - for (unsigned int i = 0; i < strlen(); i++) { - str[i] = ::toupper(str[i]); - } - - return *this; -} - -String & String::tolower() { - for (unsigned int i = 0; i < strlen(); i++) { - str[i] = ::tolower(str[i]); - } - - return *this; -} - -String String::ltrim() const { - char * d = (char *) malloc(strlen() + 1), * p, * r; - int s; - - r = d; - - for (p = str; *p && *p == ' '; p++); - for (s = 0; *p; *(d++) = *(p++), s++); - *d = 0; - - return String(s, r); -} - -String String::rtrim() const { - char * d = strdup(), * r; - int s = strlen(); - - r = d; - - for (d += s - 1; s && (*d == ' '); *(d--) = 0, s--); - - return String(s, r); -} - -String String::trim() const { - return rtrim().ltrim(); -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: String.cc,v 1.35 2004-11-27 21:35:19 pixel Exp $ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <iostream>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef HAVE_GMP
+#include <gmpxx.h>
+#endif
+#include "BString.h"
+#include "Exceptions.h"
+#include "gettext.h"
+
+char ** gruikptr;
+
+extern "C" {
+ double dateCalc(char *, char *);
+ int isDateArgument(char *);
+}
+
+char String::t[BUFSIZ + 1];
+
+String::String(const String & s) : str(Base::strdup(s.str)), siz(s.siz) {
+#ifdef DEBUG
+ fprintf(stderr, _("Duplicating string `%s', from %p to %p, from this %p to this %p\n"), str, s.str, str, &s, this);
+#endif
+}
+
+#ifndef asprintf
+extern "C" int asprintf(char **, const char *, ...);
+#endif
+
+String::String(char c) : siz(1) {
+#ifdef DEBUG
+ fprintf(stderr, _("Creating a string with `%c' at %p, this = %p\n"), c, str, this);
+#endif
+#ifndef HAVE_ASPRINTF
+ char * t = (char *) malloc(2);
+ sprintf(t, "%c", c);
+ str = t;
+#else
+ asprintf(&str, "%c", c);
+#endif
+}
+
+String::String(const char * s) : str(Base::strdup(s)), siz(::strlen(str)) {
+#ifdef DEBUG
+ fprintf(stderr, _("Creating a string with `%s' at %p from %p, this = %p\n"), str, str, s, this);
+#endif
+}
+
+String::String(int hs, char * s) : str(s), siz(hs) {
+#ifdef DEBUG
+ fprintf(stderr, _("Fast-Creating a string with `%s' at %p from %p, this = %p\n"), str, str, s, this);
+#endif
+}
+
+String::String(int i) {
+#ifndef HAVE_ASPRINTF
+ char t[20];
+ sprintf(t, "%i", i);
+ str = Base::strdup(t);
+#else
+ asprintf(&str, "%i", i);
+#endif
+ siz = ::strlen(str);
+}
+
+String::String(unsigned int i) {
+#ifndef HAVE_ASPRINTF
+ char t[20];
+ sprintf(t, "%u", i);
+ str = Base::strdup(t);
+#else
+ asprintf(&str, "%u", i);
+#endif
+ siz = ::strlen(str);
+}
+
+String::String(int64 l) {
+#ifndef HAVE_ASPRINTF
+ char t[40];
+ sprintf(t, "%lld", l);
+ str = Base::strdup(t);
+#else
+ asprintf(&str, "%lld", l);
+#endif
+ siz = ::strlen(str);
+}
+
+String::String(Uint64 l) {
+#ifndef HAVE_ASPRINTF
+ char t[40];
+ sprintf(t, "%llu", l);
+ str = Base::strdup(t);
+#else
+ asprintf(&str, "%llu", l);
+#endif
+ siz = ::strlen(str);
+}
+
+String::String(double d) {
+#ifndef HAVE_ASPRINTF
+ char t[30];
+ sprintf(t, "%g", d);
+ str = Base::strdup(t);
+#else
+ asprintf(&str, "%g", d);
+#endif
+ siz = ::strlen(str);
+}
+
+String::~String() {
+#ifdef DEBUG
+ fprintf(stderr, _("Destroying string @ %p, freeing %p.\n"), this, str);
+#endif
+ free(str);
+}
+
+const char * String::set(const char * s, va_list ap) {
+ const char * r;
+ free(str);
+ if (!s) {
+ str = Base::strdup("");
+ return str;
+ }
+
+#ifdef HAVE_GMP
+ gmp_vasprintf(&str, s, ap);
+ r = str;
+#else // !HAVE_GMP
+#ifdef HAVE_VASPRINTF
+ vasprintf(&str, s, ap);
+ r = str;
+#else // !HAVE_VASPRINTF
+#ifdef HAVE_VSNPRINTF
+ LOCK;
+ vsnprintf(t, BUFSIZ, s, ap);
+ str = Base::strdup(r = t);
+ UNLOCK;
+#else // !HAVE_VSNPRINTF
+#ifdef _WIN32
+#ifdef _MSC_VER
+ r = str = (char *) malloc(_vscprintf(s, ap) + 1);
+ vsprintf(str, s, ap);
+#else
+ LOCK;
+ _vsnprintf(t, BUFSIZ, s, ap);
+ str = Base::strdup(r = t);
+ UNLOCK;
+#endif
+#else
+ LOCK;
+ vsprintf(t, s, ap);
+ str = Base::strdup(r = t);
+ UNLOCK;
+#endif
+#endif // HAVE_VSNPRINTF
+#endif // HAVE_VASPRINTF
+#endif // HAVE_GMP
+ siz = ::strlen(str);
+ return r;
+}
+
+const char * String::set(const char * s, ...) {
+ const char * r;
+ va_list ap;
+ va_start(ap, s);
+ r = set(s, ap);
+ va_end(ap);
+ return r;
+}
+
+const char * String::set(const ugly_string & s, ...) {
+ const char * r;
+ va_list ap;
+ va_start(ap, s);
+ r = set(s.p, ap);
+ va_end(ap);
+ return r;
+}
+
+#ifdef HAVE_VSSCANF
+int String::scanf(const char * s, ...) const {
+ va_list ap;
+ int t;
+
+ va_start(ap, s);
+#ifdef HAVE_GMP
+ t = gmp_vsscanf(str, s, ap);
+#else
+ t = vsscanf(str, s, ap);
+#endif
+ va_end(ap);
+ return t;
+}
+
+int String::scanf(const ugly_string & s, ...) const {
+ va_list ap;
+ int t;
+
+ va_start(ap, s);
+#ifdef HAVE_GMP
+ t = gmp_vsscanf(str, s.p, ap);
+#else
+ t = vsscanf(str, s.p, ap);
+#endif
+ va_end(ap);
+ return t;
+}
+#endif
+
+const char * String::to_charp(size_t from, ssize_t to) const {
+ if (to < 0) {
+ if (from)
+ strncpy(t, &(str[from]), BUFSIZ);
+ else
+ return str;
+ } else {
+ if (((size_t) to) >= siz) {
+ to = siz - 1;
+ }
+
+ if ((((size_t) to) - from) > BUFSIZ) {
+ from -= (to - from) - BUFSIZ;
+ }
+
+ if (((size_t) to) >= from) {
+ size_t i;
+ for (i = 0; i <= ((size_t) to) - from; i++) {
+ t[i] = str[i + from];
+ }
+ t[i] = '\0';
+ } else {
+ t[0] = '\0';
+ }
+ }
+ return t;
+}
+
+String String::extract(size_t from, ssize_t to) const {
+ return String(to_charp(from, to));
+}
+
+char * String::strdup(size_t from, ssize_t to) const {
+ char * r;
+
+ LOCK;
+ r = Base::strdup(to_charp(from, to));
+ UNLOCK;
+
+ return r;
+}
+
+int String::to_int(void) const {
+ int r;
+
+ sscanf(str, "%i", &r);
+ return r;
+}
+
+double String::to_double(void) const {
+ double r;
+
+ sscanf(str, "%lf", &r);
+ return r;
+}
+
+String & String::operator=(const String & s) {
+ if (str != s.str) {
+ // On évite l'autodestruction...
+ free(str);
+ str = s.strdup();
+ siz = s.siz;
+ }
+ return *this;
+}
+
+String String::operator+(const String & s) const {
+ char * t = (char *) malloc(s.siz + siz + 1), * u;
+
+ strcpy((u = t), str);
+ u += siz;
+ strcpy(u, s.str);
+ return String(siz + s.siz, t);
+}
+
+String & String::operator+=(const String & s) {
+ char * t = (char *) malloc(s.siz + siz + 1), * u;
+
+ strcpy((u = t), str);
+ u += siz;
+ strcat(u, s.str);
+ free(str);
+ str = t;
+ siz += s.siz;
+ return (*this);
+}
+
+std::ostream & operator<<(std::ostream & os, const String & s) {
+ return (os << s.to_charp());
+}
+
+std::istream & operator>>(std::istream & is, String & s) {
+ char c = 0;
+
+ s.set("");
+
+ while (!is.eof()) {
+ c = is.get();
+ if (c == '\n') return is;
+ if (c == '\r') continue;
+ s += c;
+ }
+
+ return is;
+}
+
+bool String::operator!=(const String & s) const {
+ return (strcmp(str, s.str) != 0);
+}
+
+bool String::operator==(const String & s) const {
+ return (strcmp(str, s.str) == 0);
+}
+
+bool String::operator<=(const String & s) const {
+ return (strcmp(str, s.str) <= 0);
+}
+
+bool String::operator>=(const String & s) const {
+ return (strcmp(str, s.str) >= 0);
+}
+
+bool String::operator<(const String & s) const {
+ return (strcmp(str, s.str) < 0);
+}
+
+bool String::operator>(const String & s) const {
+ return (strcmp(str, s.str) > 0);
+}
+
+size_t String::strlen() const {
+ return (siz);
+}
+
+char String::operator[](size_t i) const {
+ if (i >= siz) {
+ return 0;
+ } else {
+ return str[i];
+ }
+}
+
+char & String::operator[](size_t i) {
+ static char zero = 0;
+
+ if (i >= siz) {
+ return zero;
+ } else {
+ return str[i];
+ }
+}
+
+ssize_t String::strchr(char c, size_t from) const {
+ for (size_t i = from; i < siz; i++) {
+ if (str[i] == c) return i;
+ }
+
+ return -1;
+}
+
+ssize_t String::strrchr(char c) const {
+ for (size_t i = siz - 1; i >= 0; i--) {
+ if (str[i] == c) return i;
+ }
+
+ return -1;
+}
+
+ssize_t String::strstr(const String & s) const {
+ char * p = ::strstr(str, s.str);
+
+ if (p) {
+ return p - str;
+ } else {
+ return -1;
+ }
+}
+
+int String::strchrcnt(char c) const {
+ size_t i, cnt = 0;
+ for (i = 0; i < siz; i++) {
+ if (str[i] == c) cnt++;
+ }
+
+ return cnt;
+}
+
+String String::to_sqldate(void) const {
+/* DD/MM/YYYY ==> YYYYMMMDD */
+ return (is_date() ? extract(6, 9) + extract(3, 4) + extract(0, 1) : "");
+}
+
+String String::to_sqltime(void) const {
+/* h:m ==> h * 60 + m */
+ int p = strchr(':');
+ return (is_time() ? String(extract(0, p - 1).to_int() * 60 + extract(p + 1).to_int()) : "");
+}
+
+String String::from_sqldate(void) const {
+/* YYYYMMDD ==> DD/MM/YYYY */
+ return ((strlen() == 8) && is_number() ? extract(6, 7) + '/' + extract(4, 5) + '/' + extract(0, 3) : "");
+}
+
+String String::from_sqltime(void) const {
+/* t ==> (t / 60):(t % 60) */
+ int t = to_int();
+ return (is_number() ? String((int) (t / 60)) + ':' + (t % 60) : "");
+}
+
+bool String::is_date(void) const {
+/* 'DD/MM/YYYY'
+ 0123456789 */
+
+ if (strlen() != 10) return false;
+ if ((str[2] != '/') || (str[5] != '/') ||
+ (!extract(0, 1).is_number()) ||
+ (!extract(3, 4).is_number()) ||
+ (!extract(6, 9).is_number())) {
+ return (isDateArgument(to_sqldate().str) != 0);
+ }
+
+ return true;
+}
+
+double String::datedif(const String & s) const {
+ double r;
+ if (is_date() && s.is_date()) {
+ r = dateCalc(str, s.str);
+ return r < 0 ? -r : r;
+ }
+
+ return -1;
+}
+
+bool String::is_number(void) const {
+ for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) {
+ if ((str[i] > '9') || (str[i] < '0')) return false;
+ }
+ return true;
+}
+
+bool String::is_float(void) const {
+ bool seendot = false;
+
+ for (size_t i = ((str[0] == '-') ? 1 : 0); i < siz; i++) {
+ if ((str[i] > '9') || (str[i] < '0')) {
+ if ((str[i] == '.') && !seendot) {
+ seendot = true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool String::is_time(void) const {
+ int p = strchr(':');
+
+ if (p == -1) return false;
+
+ // On accepte les heures sous le format xxxxxx:yy pour pouvoir indiquer des durées.
+
+ if ((!extract(0, p - 1).is_number()) || (!extract(p + 1).is_number()))
+ return false;
+
+ return (extract(p + 1).to_int() < 60) ? true : false;
+}
+
+String operator+(const char * a, const String & b) {
+ return String(a) + b;
+}
+
+String::operator ugly_string() const {
+ ugly_string r;
+ r.p = str;
+ return r;
+}
+
+String & String::toupper() {
+ for (unsigned int i = 0; i < strlen(); i++) {
+ str[i] = ::toupper(str[i]);
+ }
+
+ return *this;
+}
+
+String & String::tolower() {
+ for (unsigned int i = 0; i < strlen(); i++) {
+ str[i] = ::tolower(str[i]);
+ }
+
+ return *this;
+}
+
+String String::ltrim() const {
+ char * d = (char *) malloc(strlen() + 1), * p, * r;
+ int s;
+
+ r = d;
+
+ for (p = str; *p && *p == ' '; p++);
+ for (s = 0; *p; *(d++) = *(p++), s++);
+ *d = 0;
+
+ return String(s, r);
+}
+
+String String::rtrim() const {
+ char * d = strdup(), * r;
+ int s = strlen();
+
+ r = d;
+
+ for (d += s - 1; s && (*d == ' '); *(d--) = 0, s--);
+
+ return String(s, r);
+}
+
+String String::trim() const {
+ return rtrim().ltrim();
+}
diff --git a/lib/Table.cc b/lib/Table.cc index 2509e4e..7d0941a 100644 --- a/lib/Table.cc +++ b/lib/Table.cc @@ -1,50 +1,50 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Table.h" -#include "HttpServ.h" -#include "CopyJob.h" -#include "Buffer.h" - -Table::Table(const String & titre, const String & url, String * heads, String * cells, int nbc, int nbl, Action * na) : - Action(url), tit(titre), hds(heads), cls(cells), nc(nbc), nl(nbl), Next(na) { } - -String Table::GetTitle(void) { - return tit; -} - -Task * Table::Do(Variables * v, Variables *, Handle * h) { - Handle * b = new Buffer(); - Task * t = new CopyJob(b, h, -1, true); - - SendHead(b); - - (*b) << "<center><TABLE BORDER=0>" << endnl; - - if (hds) { - (*b) << "<TR>" << endnl; - for (int i = 0; i < nc; i++) { - (*b) << "<TH BGCOLOR=\"#bbbbbb\">" << hds[i] << "</TH>" << endnl; - } - (*b) << "</TR>" << endnl; - } - - for (int l = 0; l < nl; l++) { - (*b) << "<TR>" << endnl; - for (int c = 0; c < nc; c++) { - (*b) << "<TD BGCOLOR=\"#" << (l % 2 ? "cccccc" : "dddddd") << "\">" << cls[l * nc + c] << "</TD>" << endnl; - } - (*b) << "</TR>" << endnl; - } - - (*b) << "</TABLE>" - -"<FORM METHOD=\"POST\" ACTION=\"/bin/" << (Next ? Next->GetURL() : "start") << "\">" << endnl << -"<INPUT TYPE=\"SUBMIT\" VALUE=\" Ok \">" << endnl; -(*b) << "</FORM></CENTER>" << endnl; - - SendFoot(b); - Accessed(); - - return t; -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Table.h"
+#include "HttpServ.h"
+#include "CopyJob.h"
+#include "Buffer.h"
+
+Table::Table(const String & titre, const String & url, String * heads, String * cells, int nbc, int nbl, Action * na) :
+ Action(url), tit(titre), hds(heads), cls(cells), nc(nbc), nl(nbl), Next(na) { }
+
+String Table::GetTitle(void) {
+ return tit;
+}
+
+Task * Table::Do(Variables * v, Variables *, Handle * h) {
+ Handle * b = new Buffer();
+ Task * t = new CopyJob(b, h, -1, true);
+
+ SendHead(b);
+
+ (*b) << "<center><TABLE BORDER=0>" << endnl;
+
+ if (hds) {
+ (*b) << "<TR>" << endnl;
+ for (int i = 0; i < nc; i++) {
+ (*b) << "<TH BGCOLOR=\"#bbbbbb\">" << hds[i] << "</TH>" << endnl;
+ }
+ (*b) << "</TR>" << endnl;
+ }
+
+ for (int l = 0; l < nl; l++) {
+ (*b) << "<TR>" << endnl;
+ for (int c = 0; c < nc; c++) {
+ (*b) << "<TD BGCOLOR=\"#" << (l % 2 ? "cccccc" : "dddddd") << "\">" << cls[l * nc + c] << "</TD>" << endnl;
+ }
+ (*b) << "</TR>" << endnl;
+ }
+
+ (*b) << "</TABLE>"
+
+"<FORM METHOD=\"POST\" ACTION=\"/bin/" << (Next ? Next->GetURL() : "start") << "\">" << endnl <<
+"<INPUT TYPE=\"SUBMIT\" VALUE=\" Ok \">" << endnl;
+(*b) << "</FORM></CENTER>" << endnl;
+
+ SendFoot(b);
+ Accessed();
+
+ return t;
+}
diff --git a/lib/Task.cc b/lib/Task.cc index afa697c..55a4540 100644 --- a/lib/Task.cc +++ b/lib/Task.cc @@ -1,110 +1,110 @@ -#include <sys/time.h> -#include <iostream> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "TaskMan.h" -#include "Task.h" -#include "BString.h" -#include "gettext.h" - -Task::Task() : current(0), state(TASK_ON_HOLD), stopped(false), suspended(false), wbta(0) { - TaskMan::AddTask(this); -} - -Task::~Task() { - TaskMan::RemoveFromWatches(this); -} - -int Task::Do() throw (GeneralException) { - return TASK_ON_HOLD; -} - -int Task::Run() { - try { - state = Do(); - } - catch (TaskSwitch) { - return state; - } - catch (GeneralException e) { - std::cerr << _("Task ") << GetName() << _(" caused an unexpected exception: \"") << e.GetMsg() << _("\". Terminating.\n"); - state = TASK_DONE; - return TASK_DONE; - } - - return state; -} - -int Task::DryRun() { - while (state != TASK_DONE) { - try { - state = Do(); - } - catch (TaskSwitch) { - } - catch (GeneralException e) { - std::cerr << _("Task ") << GetName() << _(" caused an unexpected exception during dry-run: \"") << e.GetMsg() << _("\". Terminating.\n"); - state = TASK_DONE; - } - } - - return state; -} - -int Task::GetState() { - return state; -} - -String Task::GetName() { - return _("Unknow Task"); -} - -void Task::Suspend(int newstate) throw (GeneralException) { - if (newstate != -1) { - state = newstate; - } - suspended = true; - throw TaskSwitch(); -} - -void Task::WaitFor(Handle * h, int flags) { - h->SetNonBlock(); - TaskMan::WaitFor(h, this, flags); -} - -void Task::WaitFor(Task * t) { - t->wbta = this; -} - -void Task::WaitFor(pid_t p) { - TaskMan::WaitFor(p, this); -} - -void Task::WaitFor(timeval t, int flags) { - TaskMan::WaitFor(t, this, flags); -} - -void Task::SetBurst() { - state = TASK_BURST; -} - -void Task::Stop() { - stopped = true; -} - -void Task::Restart() { - stopped = false; -} - -bool Task::IsStopped() { - return stopped; -} - -Task * Task::WaitedBy() { - return wbta; -} - -void Task::RemoveFromWatches() { - wbta = 0; -} +#include <sys/time.h>
+#include <iostream>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "TaskMan.h"
+#include "Task.h"
+#include "BString.h"
+#include "gettext.h"
+
+Task::Task() : current(0), state(TASK_ON_HOLD), stopped(false), suspended(false), wbta(0) {
+ TaskMan::AddTask(this);
+}
+
+Task::~Task() {
+ TaskMan::RemoveFromWatches(this);
+}
+
+int Task::Do() throw (GeneralException) {
+ return TASK_ON_HOLD;
+}
+
+int Task::Run() {
+ try {
+ state = Do();
+ }
+ catch (TaskSwitch) {
+ return state;
+ }
+ catch (GeneralException e) {
+ std::cerr << _("Task ") << GetName() << _(" caused an unexpected exception: \"") << e.GetMsg() << _("\". Terminating.\n");
+ state = TASK_DONE;
+ return TASK_DONE;
+ }
+
+ return state;
+}
+
+int Task::DryRun() {
+ while (state != TASK_DONE) {
+ try {
+ state = Do();
+ }
+ catch (TaskSwitch) {
+ }
+ catch (GeneralException e) {
+ std::cerr << _("Task ") << GetName() << _(" caused an unexpected exception during dry-run: \"") << e.GetMsg() << _("\". Terminating.\n");
+ state = TASK_DONE;
+ }
+ }
+
+ return state;
+}
+
+int Task::GetState() {
+ return state;
+}
+
+String Task::GetName() {
+ return _("Unknow Task");
+}
+
+void Task::Suspend(int newstate) throw (GeneralException) {
+ if (newstate != -1) {
+ state = newstate;
+ }
+ suspended = true;
+ throw TaskSwitch();
+}
+
+void Task::WaitFor(Handle * h, int flags) {
+ h->SetNonBlock();
+ TaskMan::WaitFor(h, this, flags);
+}
+
+void Task::WaitFor(Task * t) {
+ t->wbta = this;
+}
+
+void Task::WaitFor(pid_t p) {
+ TaskMan::WaitFor(p, this);
+}
+
+void Task::WaitFor(timeval t, int flags) {
+ TaskMan::WaitFor(t, this, flags);
+}
+
+void Task::SetBurst() {
+ state = TASK_BURST;
+}
+
+void Task::Stop() {
+ stopped = true;
+}
+
+void Task::Restart() {
+ stopped = false;
+}
+
+bool Task::IsStopped() {
+ return stopped;
+}
+
+Task * Task::WaitedBy() {
+ return wbta;
+}
+
+void Task::RemoveFromWatches() {
+ wbta = 0;
+}
diff --git a/lib/TaskMan.cc b/lib/TaskMan.cc index 1dcf331..89d65be 100644 --- a/lib/TaskMan.cc +++ b/lib/TaskMan.cc @@ -1,456 +1,456 @@ -#include <signal.h> -#include <sys/wait.h> -#include <sys/poll.h> -#include <errno.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> -#include <vector> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "TaskMan.h" -#include "gettext.h" - -#define USE_POLL 1 - -TaskMan::TaskList_t TaskMan::TaskList; -TaskMan::TaskList_t TaskMan::Zombies; -std::vector<TaskMan::w4ha_t> TaskMan::w4ha; -std::vector<TaskMan::w4pr_t> TaskMan::w4pr; -std::vector<TaskMan::w4to_t> TaskMan::w4to; -bool TaskMan::stopped = false; - -int TaskMan::number = 0; -bool TaskMan::inited = false; - -int TaskMan::event, TaskMan::eprocess, TaskMan::estatus; -Task * TaskMan::etask; -Handle * TaskMan::ehandle; - -sigset_t TaskMan::sigchildset; - -static int got_sigchild = 0; - -void taskman_sigchild(int sig) { - int status; - pid_t pid; - - pid = wait(&status); - if (TaskMan::GotChild(pid, status)) { - got_sigchild++; - } else { - TaskMan::WaitFor(pid, 0, status); - } - -// cerr << "Got SIGCHILD, pid = " << pid << " and status = " << status << endl; - signal(SIGCHLD, taskman_sigchild); -} - -void taskman_sighole(int sig) { - signal(sig, taskman_sighole); -} - -int TaskMan::GotChild(pid_t pid, int status) { - int r = 0; - unsigned int i; - - for (i = 0; i < w4pr.size(); i++) { - if (w4pr[i].pr == pid) { - w4pr[i].flag = true; - w4pr[i].status = status; - r = 1; - } - } - - return r; -} - -void TaskMan::Init() throw (GeneralException) { - if (inited) { - throw GeneralException(_("Task Manager already initialised.")); - } - - signal(SIGCHLD, taskman_sigchild); - signal(SIGPIPE, taskman_sighole); - signal(SIGHUP, taskman_sighole); - - sigemptyset(&sigchildset); - sigaddset(&sigchildset, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigchildset, 0); - - inited = true; - number = 0; -} - -void TaskMan::Stop() { - stopped = true; -} - -int TaskMan::Event() { - return event; -} - -Task * TaskMan::Etask() { - return etask; -} - -Handle * TaskMan::Ehandle() { - return ehandle; -} - -int TaskMan::Eprocess() { - return eprocess; -} - -int TaskMan::Estatus() { - return estatus; -} - -void TaskMan::AddTask(Task * t) { - if (!inited) { - Init(); - } - - if (t) { - TaskList.push_back(t); - number++; - } -} - -std::vector<Task *>::iterator TaskMan::FindTask(Task * t) throw (GeneralException) { - if (!inited) { - Init(); - } - - if (TaskList.empty()) - throw TaskNotFound(); - - for (std::vector<Task *>::iterator p = TaskList.begin(); p != TaskList.end(); p++) { - if (*p == t) { - return p; - } - } - - throw TaskNotFound(); -} - -void TaskMan::RemoveFromWatches(Task * t) { - if (!w4ha.empty()) { - for (std::vector<w4ha_t>::iterator p = w4ha.begin(); p != w4ha.end(); p++) { - if (p->T == t) { - w4ha.erase(p); - p--; - } - } - } - - if (!w4pr.empty()) { - for (std::vector<w4pr_t>::iterator p = w4pr.begin(); p != w4pr.end(); p++) { - if (p->T == t) { - w4pr.erase(p); - p--; - } - } - } - - if (!w4to.empty()) { - for (std::vector<w4to_t>::iterator p = w4to.begin(); p != w4to.end(); p++) { - if (p->T == t) { - w4to.erase(p); - p--; - } - } - } - - if (!TaskList.empty()) { - for (TaskList_t::iterator p = TaskList.begin(); p != TaskList.end(); p++) { - if ((*p)->WaitedBy() == t) { - Zombies.push_back(*p); - (*p)->RemoveFromWatches(); - TaskList.erase(p); - number--; - p--; - } else if ((*p) == t) { - TaskList.erase(p); - number--; - p--; - } - } - } -} - -void TaskMan::WaitFor(Handle * h, Task * t, int flags) { - h->SetNonBlock(); - w4ha.push_back(w4ha_t(h, flags, t)); -} - -void TaskMan::WaitFor(pid_t pid, Task * t, int status) { - if (status == -1) { - if (!w4pr.empty()) { - for (std::vector<w4pr_t>::iterator p = w4pr.begin(); p != w4pr.end(); p++) { - if (p->pr == pid) { - p->T = t; - p->flag = true; - got_sigchild++; - return; - } - } - } - } - w4pr.push_back(w4pr_t(pid, t)); - w4pr[w4pr.size() - 1].status = status; -} - -void TaskMan::WaitFor(timeval t, Task * T, int flags) { - w4to.push_back(w4to_t(t, flags, T)); -} - -void TaskMan::MainLoop() throw (GeneralException) { - struct pollfd * ufsd; - unsigned int nfds; - - int no_burst; - - if (!inited) { - Init(); - } - - while (1) { - if (number == 0) { - throw GeneralException(_("TaskMan: No more task to manage.")); - } - - if (stopped) return; - -// cerr << "-=- TaskMan: begin main loop with " << number << " task to manage.\n"; - if (!TaskList.empty()) { - for (TaskList_t::iterator p = TaskList.begin(); p != TaskList.end(); p++) { - Task * t = *p; -// cerr << "-=- TaskMan: task " << t->GetName() << endl; - } - } - -// cerr << "-=- TaskMan: processing burning tasks.\n"; - - no_burst = 0; - while (!no_burst) { - no_burst = 1; - /* First, we will check for any burning task and run 'em */ - event = E_BURST; - if (!TaskList.empty()) { - for (TaskList_t::iterator p = TaskList.begin(); p != TaskList.end(); p++) { - Task * t = *p; - - if (t->IsStopped()) { - continue; - } - - if (t->GetState() == TASK_BURST) { -// cerr << "-=- TaskMan: running burning task " << t->GetName() << endl; - t->Run(); - /* if the task added some new tasks, we have to rerun the loop */ - no_burst = 0; - break; - } - - if (t->GetState() == TASK_DONE) { - TaskList.erase(p); - number--; - p--; - Zombies.push_back(t); - } - } - } - } - - /* Let's compute the nearest timeout, and eventually, launch the outdated timeouts. */ - int timeout = -1; - event = E_TIMEOUT; - - if (!w4to.empty()) { - time_t curtime = time(NULL); - for (std::vector<w4to_t>::iterator p = w4to.begin(); p != w4to.end(); p++) { - int cur_to; - cur_to = (p->to.tv_sec - curtime) * 1000 + p->to.tv_usec; - if (cur_to < 0) { - - } - } - } - - /* Now is time to check all the handle and enter into a wait state. */ - - event = E_HANDLE; -// cerr << "-=- TaskMan: processing handle-waiting tasks.\n"; - - nfds = w4ha.size(); - no_burst = 1; - - if (nfds != 0) { - int r; - std::vector<w4ha_t>::iterator p; - struct pollfd * q; - - ufsd = (struct pollfd *) malloc(nfds * sizeof(struct pollfd)); - if (!w4ha.empty()) { - for (q = ufsd, p = w4ha.begin(); p != w4ha.end(); p++, q++) { - p->dirthy = false; - if (p->T->IsStopped()) { - q->fd = 0; - q->events = 0; - } else { - if (p->ha->CanWatch()) { - q->fd = p->ha->GetHandle(); - q->events = (p->flags & W4_READING ? POLLIN : 0) | (p->flags & W4_WRITING ? POLLOUT : 0); - } else { - p->T->SetBurst(); - no_burst = 0; - p->dirthy = true; - if (!(p->flags & W4_STICKY)) { - w4ha.erase(p); - p--; - } - q->fd = 0; - q->events = 0; - } - } - } - } - - sigprocmask(SIG_UNBLOCK, &sigchildset, 0); - r = poll(ufsd, nfds, (no_burst) && !(Zombies.size()) && !(got_sigchild) ? -1: 0); - sigprocmask(SIG_BLOCK, &sigchildset, 0); - - if (r < 0) { - if (errno != EINTR) { - throw GeneralException(String(_("Error during poll: ")) + strerror(errno)); - } - } else if (r == 0) { - // timeout. - // **FIXME** -#warning FIXME - } else { - int fd; - struct pollfd * q; - unsigned int i; - for (q = ufsd, i = 0; i < nfds; i++, q++) { - if (q->revents & POLLNVAL) { - throw GeneralException(String(_("Error with poll, handle ")) + q->fd + _(" invalid.")); - } - -// if (q->revents & POLLERR) { -// cerr << _("Error condition with poll, handle ") << q->fd << endl; -// } - -// if (q->revents & POLLHUP) { -// cerr << _("Handle ") << q->fd << _(" hung up.\n"); -// } - - fd = q->fd; - if (q->revents & (POLLIN | POLLOUT | POLLERR | POLLHUP)) { - // We have to look into the handle structure now... - bool touched; - if (!w4ha.empty()) { - for (std::vector<w4ha_t>::iterator p = w4ha.begin(); p != w4ha.end(); p = touched ? w4ha.begin() : p + 1) { - touched = false; - if ((p->ha->GetHandle() == fd) && (!p->T->IsStopped()) && (p->T->GetState() != TASK_DONE) && (!p->dirthy)) { - // We've got one, launch it. -// cerr << "-=- TaskMan: launching task " << p->T->GetName() << " for handle " << p->ha->GetHandle() << endl; - w4ha_t w4 = *p; - p->dirthy = true; - - if (!(p->flags & W4_STICKY)) { - w4ha.erase(p); - } - - touched = true; - - ehandle = p->ha; - w4.T->Run(); - - if (w4.T->GetState() == TASK_DONE) { - // This task died, remove it. - try { - std::vector<Task *>::iterator q = FindTask(w4.T); - TaskList.erase(q); - number--; - Zombies.push_back(w4.T); - } - catch (TaskNotFound) { - } - } - } - } - } - } - } - } - free(ufsd); - } - - /* And finally, let's clean-up all the zombies around here. */ - - int no_zombies; - no_zombies = 0; - - event = E_TASK; -// cerr << "-=- TaskMan: processing zombies loop.\n"; - - while (!no_zombies) { - no_zombies = 1; - while (Zombies.size()) { - Task * t = Zombies[0], * o; - - if (!t) { -// cerr << "!?!?!? We have t = NULL ?!?!?! WTF\n"; - break; - } - - if ((o = t->WaitedBy())) { -// cerr << "-=- TaskMan: running task " << o->GetName() << " for task " << t->GetName() << endl; - etask = t; - o->Run(); - - if (o->GetState() == TASK_DONE) { - TaskList_t::iterator f = FindTask(o); - TaskList.erase(f); - number--; - Zombies.push_back(o); - no_zombies = 0; - } - } else { - delete t; - } - Zombies.erase(Zombies.begin()); - } - } - - /* To end up the loop, let's recall task waiting for processes */ - - event = E_PROCESS; -// cerr << "-=- TaskMan: processing child-waiting tasks.\n"; - - if (got_sigchild) { - if (!w4pr.empty()) { - for (std::vector<w4pr_t>::iterator p = w4pr.begin(); p != w4pr.end(); p++) { - if (p->flag) { - Task * t; - if (p->T->IsStopped()) { - continue; - } - eprocess = p->pr; - estatus = p->status; -// cerr << "-=- TaskMan: running task " << p->T->GetName() << " for process " << p->pr << " (" << p->status << ")\n"; - t = p->T; - w4pr.erase(p); - got_sigchild--; - t->Run(); - break; - } - } - } - } - } -} +#include <signal.h>
+#include <sys/wait.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <vector>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "TaskMan.h"
+#include "gettext.h"
+
+#define USE_POLL 1
+
+TaskMan::TaskList_t TaskMan::TaskList;
+TaskMan::TaskList_t TaskMan::Zombies;
+std::vector<TaskMan::w4ha_t> TaskMan::w4ha;
+std::vector<TaskMan::w4pr_t> TaskMan::w4pr;
+std::vector<TaskMan::w4to_t> TaskMan::w4to;
+bool TaskMan::stopped = false;
+
+int TaskMan::number = 0;
+bool TaskMan::inited = false;
+
+int TaskMan::event, TaskMan::eprocess, TaskMan::estatus;
+Task * TaskMan::etask;
+Handle * TaskMan::ehandle;
+
+sigset_t TaskMan::sigchildset;
+
+static int got_sigchild = 0;
+
+void taskman_sigchild(int sig) {
+ int status;
+ pid_t pid;
+
+ pid = wait(&status);
+ if (TaskMan::GotChild(pid, status)) {
+ got_sigchild++;
+ } else {
+ TaskMan::WaitFor(pid, 0, status);
+ }
+
+// cerr << "Got SIGCHILD, pid = " << pid << " and status = " << status << endl;
+ signal(SIGCHLD, taskman_sigchild);
+}
+
+void taskman_sighole(int sig) {
+ signal(sig, taskman_sighole);
+}
+
+int TaskMan::GotChild(pid_t pid, int status) {
+ int r = 0;
+ unsigned int i;
+
+ for (i = 0; i < w4pr.size(); i++) {
+ if (w4pr[i].pr == pid) {
+ w4pr[i].flag = true;
+ w4pr[i].status = status;
+ r = 1;
+ }
+ }
+
+ return r;
+}
+
+void TaskMan::Init() throw (GeneralException) {
+ if (inited) {
+ throw GeneralException(_("Task Manager already initialised."));
+ }
+
+ signal(SIGCHLD, taskman_sigchild);
+ signal(SIGPIPE, taskman_sighole);
+ signal(SIGHUP, taskman_sighole);
+
+ sigemptyset(&sigchildset);
+ sigaddset(&sigchildset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigchildset, 0);
+
+ inited = true;
+ number = 0;
+}
+
+void TaskMan::Stop() {
+ stopped = true;
+}
+
+int TaskMan::Event() {
+ return event;
+}
+
+Task * TaskMan::Etask() {
+ return etask;
+}
+
+Handle * TaskMan::Ehandle() {
+ return ehandle;
+}
+
+int TaskMan::Eprocess() {
+ return eprocess;
+}
+
+int TaskMan::Estatus() {
+ return estatus;
+}
+
+void TaskMan::AddTask(Task * t) {
+ if (!inited) {
+ Init();
+ }
+
+ if (t) {
+ TaskList.push_back(t);
+ number++;
+ }
+}
+
+std::vector<Task *>::iterator TaskMan::FindTask(Task * t) throw (GeneralException) {
+ if (!inited) {
+ Init();
+ }
+
+ if (TaskList.empty())
+ throw TaskNotFound();
+
+ for (std::vector<Task *>::iterator p = TaskList.begin(); p != TaskList.end(); p++) {
+ if (*p == t) {
+ return p;
+ }
+ }
+
+ throw TaskNotFound();
+}
+
+void TaskMan::RemoveFromWatches(Task * t) {
+ if (!w4ha.empty()) {
+ for (std::vector<w4ha_t>::iterator p = w4ha.begin(); p != w4ha.end(); p++) {
+ if (p->T == t) {
+ w4ha.erase(p);
+ p--;
+ }
+ }
+ }
+
+ if (!w4pr.empty()) {
+ for (std::vector<w4pr_t>::iterator p = w4pr.begin(); p != w4pr.end(); p++) {
+ if (p->T == t) {
+ w4pr.erase(p);
+ p--;
+ }
+ }
+ }
+
+ if (!w4to.empty()) {
+ for (std::vector<w4to_t>::iterator p = w4to.begin(); p != w4to.end(); p++) {
+ if (p->T == t) {
+ w4to.erase(p);
+ p--;
+ }
+ }
+ }
+
+ if (!TaskList.empty()) {
+ for (TaskList_t::iterator p = TaskList.begin(); p != TaskList.end(); p++) {
+ if ((*p)->WaitedBy() == t) {
+ Zombies.push_back(*p);
+ (*p)->RemoveFromWatches();
+ TaskList.erase(p);
+ number--;
+ p--;
+ } else if ((*p) == t) {
+ TaskList.erase(p);
+ number--;
+ p--;
+ }
+ }
+ }
+}
+
+void TaskMan::WaitFor(Handle * h, Task * t, int flags) {
+ h->SetNonBlock();
+ w4ha.push_back(w4ha_t(h, flags, t));
+}
+
+void TaskMan::WaitFor(pid_t pid, Task * t, int status) {
+ if (status == -1) {
+ if (!w4pr.empty()) {
+ for (std::vector<w4pr_t>::iterator p = w4pr.begin(); p != w4pr.end(); p++) {
+ if (p->pr == pid) {
+ p->T = t;
+ p->flag = true;
+ got_sigchild++;
+ return;
+ }
+ }
+ }
+ }
+ w4pr.push_back(w4pr_t(pid, t));
+ w4pr[w4pr.size() - 1].status = status;
+}
+
+void TaskMan::WaitFor(timeval t, Task * T, int flags) {
+ w4to.push_back(w4to_t(t, flags, T));
+}
+
+void TaskMan::MainLoop() throw (GeneralException) {
+ struct pollfd * ufsd;
+ unsigned int nfds;
+
+ int no_burst;
+
+ if (!inited) {
+ Init();
+ }
+
+ while (1) {
+ if (number == 0) {
+ throw GeneralException(_("TaskMan: No more task to manage."));
+ }
+
+ if (stopped) return;
+
+// cerr << "-=- TaskMan: begin main loop with " << number << " task to manage.\n";
+ if (!TaskList.empty()) {
+ for (TaskList_t::iterator p = TaskList.begin(); p != TaskList.end(); p++) {
+ Task * t = *p;
+// cerr << "-=- TaskMan: task " << t->GetName() << endl;
+ }
+ }
+
+// cerr << "-=- TaskMan: processing burning tasks.\n";
+
+ no_burst = 0;
+ while (!no_burst) {
+ no_burst = 1;
+ /* First, we will check for any burning task and run 'em */
+ event = E_BURST;
+ if (!TaskList.empty()) {
+ for (TaskList_t::iterator p = TaskList.begin(); p != TaskList.end(); p++) {
+ Task * t = *p;
+
+ if (t->IsStopped()) {
+ continue;
+ }
+
+ if (t->GetState() == TASK_BURST) {
+// cerr << "-=- TaskMan: running burning task " << t->GetName() << endl;
+ t->Run();
+ /* if the task added some new tasks, we have to rerun the loop */
+ no_burst = 0;
+ break;
+ }
+
+ if (t->GetState() == TASK_DONE) {
+ TaskList.erase(p);
+ number--;
+ p--;
+ Zombies.push_back(t);
+ }
+ }
+ }
+ }
+
+ /* Let's compute the nearest timeout, and eventually, launch the outdated timeouts. */
+ int timeout = -1;
+ event = E_TIMEOUT;
+
+ if (!w4to.empty()) {
+ time_t curtime = time(NULL);
+ for (std::vector<w4to_t>::iterator p = w4to.begin(); p != w4to.end(); p++) {
+ int cur_to;
+ cur_to = (p->to.tv_sec - curtime) * 1000 + p->to.tv_usec;
+ if (cur_to < 0) {
+
+ }
+ }
+ }
+
+ /* Now is time to check all the handle and enter into a wait state. */
+
+ event = E_HANDLE;
+// cerr << "-=- TaskMan: processing handle-waiting tasks.\n";
+
+ nfds = w4ha.size();
+ no_burst = 1;
+
+ if (nfds != 0) {
+ int r;
+ std::vector<w4ha_t>::iterator p;
+ struct pollfd * q;
+
+ ufsd = (struct pollfd *) malloc(nfds * sizeof(struct pollfd));
+ if (!w4ha.empty()) {
+ for (q = ufsd, p = w4ha.begin(); p != w4ha.end(); p++, q++) {
+ p->dirthy = false;
+ if (p->T->IsStopped()) {
+ q->fd = 0;
+ q->events = 0;
+ } else {
+ if (p->ha->CanWatch()) {
+ q->fd = p->ha->GetHandle();
+ q->events = (p->flags & W4_READING ? POLLIN : 0) | (p->flags & W4_WRITING ? POLLOUT : 0);
+ } else {
+ p->T->SetBurst();
+ no_burst = 0;
+ p->dirthy = true;
+ if (!(p->flags & W4_STICKY)) {
+ w4ha.erase(p);
+ p--;
+ }
+ q->fd = 0;
+ q->events = 0;
+ }
+ }
+ }
+ }
+
+ sigprocmask(SIG_UNBLOCK, &sigchildset, 0);
+ r = poll(ufsd, nfds, (no_burst) && !(Zombies.size()) && !(got_sigchild) ? -1: 0);
+ sigprocmask(SIG_BLOCK, &sigchildset, 0);
+
+ if (r < 0) {
+ if (errno != EINTR) {
+ throw GeneralException(String(_("Error during poll: ")) + strerror(errno));
+ }
+ } else if (r == 0) {
+ // timeout.
+ // **FIXME**
+#warning FIXME
+ } else {
+ int fd;
+ struct pollfd * q;
+ unsigned int i;
+ for (q = ufsd, i = 0; i < nfds; i++, q++) {
+ if (q->revents & POLLNVAL) {
+ throw GeneralException(String(_("Error with poll, handle ")) + q->fd + _(" invalid."));
+ }
+
+// if (q->revents & POLLERR) {
+// cerr << _("Error condition with poll, handle ") << q->fd << endl;
+// }
+
+// if (q->revents & POLLHUP) {
+// cerr << _("Handle ") << q->fd << _(" hung up.\n");
+// }
+
+ fd = q->fd;
+ if (q->revents & (POLLIN | POLLOUT | POLLERR | POLLHUP)) {
+ // We have to look into the handle structure now...
+ bool touched;
+ if (!w4ha.empty()) {
+ for (std::vector<w4ha_t>::iterator p = w4ha.begin(); p != w4ha.end(); p = touched ? w4ha.begin() : p + 1) {
+ touched = false;
+ if ((p->ha->GetHandle() == fd) && (!p->T->IsStopped()) && (p->T->GetState() != TASK_DONE) && (!p->dirthy)) {
+ // We've got one, launch it.
+// cerr << "-=- TaskMan: launching task " << p->T->GetName() << " for handle " << p->ha->GetHandle() << endl;
+ w4ha_t w4 = *p;
+ p->dirthy = true;
+
+ if (!(p->flags & W4_STICKY)) {
+ w4ha.erase(p);
+ }
+
+ touched = true;
+
+ ehandle = p->ha;
+ w4.T->Run();
+
+ if (w4.T->GetState() == TASK_DONE) {
+ // This task died, remove it.
+ try {
+ std::vector<Task *>::iterator q = FindTask(w4.T);
+ TaskList.erase(q);
+ number--;
+ Zombies.push_back(w4.T);
+ }
+ catch (TaskNotFound) {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ free(ufsd);
+ }
+
+ /* And finally, let's clean-up all the zombies around here. */
+
+ int no_zombies;
+ no_zombies = 0;
+
+ event = E_TASK;
+// cerr << "-=- TaskMan: processing zombies loop.\n";
+
+ while (!no_zombies) {
+ no_zombies = 1;
+ while (Zombies.size()) {
+ Task * t = Zombies[0], * o;
+
+ if (!t) {
+// cerr << "!?!?!? We have t = NULL ?!?!?! WTF\n";
+ break;
+ }
+
+ if ((o = t->WaitedBy())) {
+// cerr << "-=- TaskMan: running task " << o->GetName() << " for task " << t->GetName() << endl;
+ etask = t;
+ o->Run();
+
+ if (o->GetState() == TASK_DONE) {
+ TaskList_t::iterator f = FindTask(o);
+ TaskList.erase(f);
+ number--;
+ Zombies.push_back(o);
+ no_zombies = 0;
+ }
+ } else {
+ delete t;
+ }
+ Zombies.erase(Zombies.begin());
+ }
+ }
+
+ /* To end up the loop, let's recall task waiting for processes */
+
+ event = E_PROCESS;
+// cerr << "-=- TaskMan: processing child-waiting tasks.\n";
+
+ if (got_sigchild) {
+ if (!w4pr.empty()) {
+ for (std::vector<w4pr_t>::iterator p = w4pr.begin(); p != w4pr.end(); p++) {
+ if (p->flag) {
+ Task * t;
+ if (p->T->IsStopped()) {
+ continue;
+ }
+ eprocess = p->pr;
+ estatus = p->status;
+// cerr << "-=- TaskMan: running task " << p->T->GetName() << " for process " << p->pr << " (" << p->status << ")\n";
+ t = p->T;
+ w4pr.erase(p);
+ got_sigchild--;
+ t->Run();
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/Variables.cc b/lib/Variables.cc index 94c4c27..b4f93c8 100644 --- a/lib/Variables.cc +++ b/lib/Variables.cc @@ -1,85 +1,85 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "Variables.h" -#include "HttpServ.h" -#include "BString.h" - -Variables::Variables(int nb) : Vars(nb), nbvars(nb) { } - -Variables::Variables(const Variables & v) : nbvars(v.nbvars) { - for (int i = 0; i < nbvars; i++) { - Vars.push_back(v.Vars[i]); - } -} - -Variables::~Variables() { } - -void Variables::SetTo(int i, const String & s) { - Vars[i] = s; -} - -String Variables::operator[](const String & name) { - int i; - String r; - - for (i = 0; i < nbvars; i++) { - if (Vars[i].strstr(name) == 0) break; - } - - if (i == nbvars) { - r = ""; - } else { - r = Vars[i].extract(Vars[i].strchr('=') + 1); - } - - return r; -} - -String Variables::operator[](int i) { - return Vars[i]; -} - -int Variables::GetNb(void) { - return nbvars; -} - -void Variables::Dump(Handle * h, const String & format) { - int i, eqp; - String Vn, Vv; - - for (i = 0; i < nbvars; i++) { - eqp = Vars[i].strchr('='); - Vn = Vars[i].extract(0, eqp - 1); - Vv = Vars[i].extract(eqp + 1); - if (format == "") { - (*h) << "<INPUT TYPE=\"HIDDEN\" NAME=\"" << Vn << "\" VALUE=\"" << Vv << "\">" << endnl; - } else { - // Use format here... - // **FIXME** -#warning FIXME - } - } -} - -void Variables::Add(const String & s) { - nbvars++; - Vars.push_back(s); -} - -void Variables::Del(int i) { - nbvars--; - Vars.erase(Vars.begin() + i, Vars.begin() + i); -} - -void Variables::Del(const String & name) { - int i; - - for (i = 0; i < nbvars; i++) { - if (Vars[i].strstr(name) == 0) break; - } - - if (i != nbvars) { - Del(i); - } -} +#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Variables.h"
+#include "HttpServ.h"
+#include "BString.h"
+
+Variables::Variables(int nb) : Vars(nb), nbvars(nb) { }
+
+Variables::Variables(const Variables & v) : nbvars(v.nbvars) {
+ for (int i = 0; i < nbvars; i++) {
+ Vars.push_back(v.Vars[i]);
+ }
+}
+
+Variables::~Variables() { }
+
+void Variables::SetTo(int i, const String & s) {
+ Vars[i] = s;
+}
+
+String Variables::operator[](const String & name) {
+ int i;
+ String r;
+
+ for (i = 0; i < nbvars; i++) {
+ if (Vars[i].strstr(name) == 0) break;
+ }
+
+ if (i == nbvars) {
+ r = "";
+ } else {
+ r = Vars[i].extract(Vars[i].strchr('=') + 1);
+ }
+
+ return r;
+}
+
+String Variables::operator[](int i) {
+ return Vars[i];
+}
+
+int Variables::GetNb(void) {
+ return nbvars;
+}
+
+void Variables::Dump(Handle * h, const String & format) {
+ int i, eqp;
+ String Vn, Vv;
+
+ for (i = 0; i < nbvars; i++) {
+ eqp = Vars[i].strchr('=');
+ Vn = Vars[i].extract(0, eqp - 1);
+ Vv = Vars[i].extract(eqp + 1);
+ if (format == "") {
+ (*h) << "<INPUT TYPE=\"HIDDEN\" NAME=\"" << Vn << "\" VALUE=\"" << Vv << "\">" << endnl;
+ } else {
+ // Use format here...
+ // **FIXME**
+#warning FIXME
+ }
+ }
+}
+
+void Variables::Add(const String & s) {
+ nbvars++;
+ Vars.push_back(s);
+}
+
+void Variables::Del(int i) {
+ nbvars--;
+ Vars.erase(Vars.begin() + i, Vars.begin() + i);
+}
+
+void Variables::Del(const String & name) {
+ int i;
+
+ for (i = 0; i < nbvars; i++) {
+ if (Vars[i].strstr(name) == 0) break;
+ }
+
+ if (i != nbvars) {
+ Del(i);
+ }
+}
diff --git a/lib/checkargs.c b/lib/checkargs.c index 4fee446..fcd84ed 100644 --- a/lib/checkargs.c +++ b/lib/checkargs.c @@ -1,85 +1,85 @@ -/* datedif - calculates the difference in days between two dates - * Copyright (C) 2000 Micael Widell contact: xeniac@linux.nu - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <stdlib.h> -#include <string.h> - -int isDateArgument(char* dateString) { - - const int MONTHS[] = {31,0,31,30,31,30,31,31,30,31,30,31}; - int i, day, month, year; - char buffer[5]; - - /* 'today' is a valid date */ - if (strcmp(dateString, "today") == 0) - return 1; - - /* Numeric dates must be eight characters long */ - if (8 != strlen(dateString)) - return 0; - - /* Check that the date is entirely formed of numbers */ - for (i = 0; i < 8; i++) { - if (dateString[i] < '0' || dateString[i] > '9') - return 0; - } - - /* Check that the date exists */ - memset(buffer, 0, 5); - strncpy(buffer, dateString + 6, 2); - day = atoi(buffer); - strncpy(buffer, dateString + 4, 2); - month = atoi(buffer); - month -= 1; - strncpy(buffer, dateString, 4); - year = atoi(buffer); - - /* Validate month */ - if (month < 0 || month > 11) - return 0; - - /* Validating dates is simple when the date does not fall into February */ - if (1 != month) { - if (day < 1 || day > MONTHS[month]) - return 0; - } else { - int feb = 28; - - /* Februarys are a bit tougher issue */ - if (0 == year % 4) { - if (0 == year % 100) { - if (0 == year % 400) { - feb = 29; - } else { - feb = 28; - } - } else { - feb = 29; - } - } - if (day < 1 || day > feb) - return 0; - } - - /* Avoid user from using dates before 16000301, since those will result in - incorrect output */ - if(16000301 > atoi(dateString)) - return 0; - - return 1; -} +/* datedif - calculates the difference in days between two dates
+ * Copyright (C) 2000 Micael Widell contact: xeniac@linux.nu
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+int isDateArgument(char* dateString) {
+
+ const int MONTHS[] = {31,0,31,30,31,30,31,31,30,31,30,31};
+ int i, day, month, year;
+ char buffer[5];
+
+ /* 'today' is a valid date */
+ if (strcmp(dateString, "today") == 0)
+ return 1;
+
+ /* Numeric dates must be eight characters long */
+ if (8 != strlen(dateString))
+ return 0;
+
+ /* Check that the date is entirely formed of numbers */
+ for (i = 0; i < 8; i++) {
+ if (dateString[i] < '0' || dateString[i] > '9')
+ return 0;
+ }
+
+ /* Check that the date exists */
+ memset(buffer, 0, 5);
+ strncpy(buffer, dateString + 6, 2);
+ day = atoi(buffer);
+ strncpy(buffer, dateString + 4, 2);
+ month = atoi(buffer);
+ month -= 1;
+ strncpy(buffer, dateString, 4);
+ year = atoi(buffer);
+
+ /* Validate month */
+ if (month < 0 || month > 11)
+ return 0;
+
+ /* Validating dates is simple when the date does not fall into February */
+ if (1 != month) {
+ if (day < 1 || day > MONTHS[month])
+ return 0;
+ } else {
+ int feb = 28;
+
+ /* Februarys are a bit tougher issue */
+ if (0 == year % 4) {
+ if (0 == year % 100) {
+ if (0 == year % 400) {
+ feb = 29;
+ } else {
+ feb = 28;
+ }
+ } else {
+ feb = 29;
+ }
+ }
+ if (day < 1 || day > feb)
+ return 0;
+ }
+
+ /* Avoid user from using dates before 16000301, since those will result in
+ incorrect output */
+ if(16000301 > atoi(dateString))
+ return 0;
+
+ return 1;
+}
diff --git a/lib/datecalc.c b/lib/datecalc.c index ad6684a..8cf2539 100644 --- a/lib/datecalc.c +++ b/lib/datecalc.c @@ -1,78 +1,78 @@ -/* datedif - calculates the difference in days between two dates - * Copyright (C) 2000 Micael Widell contact: xeniac@linux.nu - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <time.h> -#include <stdlib.h> -#include <string.h> - - -/* Gaus's formula - days since 1.3.1600 (Gregorian calendar) */ -int days(register int n, register int m, register int y) -{ - register int cy; - if((m -= 2) <= 0){ - m += 12; y--; - } - y -= 1600; cy = y/100; - return 365*y+y/4-cy+cy/4+367*m/12+n-31; -} - - -double dateCalc(char date1[], char date2[]){ - - /* Declare the needed variables */ - char* date[2] = { date1, date2 }; - struct tm *date_tm[2]; - time_t date_time_t[2]; - double dateDifference; - int isToday[2] = { 0, 0 }; - char buffer[5]; - int day[2], month[2], year[2], i; - - - /* If any of the arguments are "today", then include today's date in the - right variables */ - for(i = 0; i < 2; i++){ - if(!strcmp(date[i], "today")){ - time(&date_time_t[i]); - date_tm[i] = localtime(&date_time_t[i]); - day[i] = (*date_tm[i]).tm_mday; - month[i] = (*date_tm[i]).tm_mon + 1; - year[i] = (*date_tm[i]).tm_year + 1900; - isToday[i] = 1; - } - } - - /* Cut out the year, month and day from 8-digit datestrings */ - for (i = 0; i < 2; i++){ - if(!isToday[i]){ - memset(buffer, 0, 5); - strncpy(buffer, &date[i][6], 2); - day[i] = atoi(buffer); - strncpy(buffer, &date[i][4], 2); - month[i] = atoi(buffer); - strncpy(buffer, date[i], 4); - year[i] = atoi(buffer); - } - } - - /* Calculate the difference */ - dateDifference = days(day[1], month[1], year[1]) - days(day[0], month[0], year[0]); - - return dateDifference; -} +/* datedif - calculates the difference in days between two dates
+ * Copyright (C) 2000 Micael Widell contact: xeniac@linux.nu
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Gaus's formula - days since 1.3.1600 (Gregorian calendar) */
+int days(register int n, register int m, register int y)
+{
+ register int cy;
+ if((m -= 2) <= 0){
+ m += 12; y--;
+ }
+ y -= 1600; cy = y/100;
+ return 365*y+y/4-cy+cy/4+367*m/12+n-31;
+}
+
+
+double dateCalc(char date1[], char date2[]){
+
+ /* Declare the needed variables */
+ char* date[2] = { date1, date2 };
+ struct tm *date_tm[2];
+ time_t date_time_t[2];
+ double dateDifference;
+ int isToday[2] = { 0, 0 };
+ char buffer[5];
+ int day[2], month[2], year[2], i;
+
+
+ /* If any of the arguments are "today", then include today's date in the
+ right variables */
+ for(i = 0; i < 2; i++){
+ if(!strcmp(date[i], "today")){
+ time(&date_time_t[i]);
+ date_tm[i] = localtime(&date_time_t[i]);
+ day[i] = (*date_tm[i]).tm_mday;
+ month[i] = (*date_tm[i]).tm_mon + 1;
+ year[i] = (*date_tm[i]).tm_year + 1900;
+ isToday[i] = 1;
+ }
+ }
+
+ /* Cut out the year, month and day from 8-digit datestrings */
+ for (i = 0; i < 2; i++){
+ if(!isToday[i]){
+ memset(buffer, 0, 5);
+ strncpy(buffer, &date[i][6], 2);
+ day[i] = atoi(buffer);
+ strncpy(buffer, &date[i][4], 2);
+ month[i] = atoi(buffer);
+ strncpy(buffer, date[i], 4);
+ year[i] = atoi(buffer);
+ }
+ }
+
+ /* Calculate the difference */
+ dateDifference = days(day[1], month[1], year[1]) - days(day[0], month[0], year[0]);
+
+ return dateDifference;
+}
diff --git a/lib/fileutils.cc b/lib/fileutils.cc index b637546..79ae576 100644 --- a/lib/fileutils.cc +++ b/lib/fileutils.cc @@ -1,81 +1,81 @@ -/* - * PSX-Tools Bundle Pack - * Copyright (C) 2002 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#else -#include <io.h> -#endif -#include "generic.h" - -unsigned long filesize(int f_iso) -{ - long curpos, length; - - curpos = lseek(f_iso, 0, SEEK_CUR); - length = lseek(f_iso, 0, SEEK_END); - lseek(f_iso, curpos, SEEK_SET); - return length; -} - -void copy(int s, int d, long size) { - long i; - unsigned char c; - long r; - - for (i = 0; (i < size) || (size < 0); i++) { - r = read(s, &c, 1); - if (r == 0) { - break; - } - write(d, &c, 1); - } -} - -unsigned long filesize(FILE * f_iso) -{ - long curpos, length; - - curpos = ftell(f_iso); - fseek(f_iso, 0, SEEK_END); - length = ftell(f_iso); - fseek(f_iso, curpos, SEEK_SET); - return length; -} - -void copy(FILE * s, FILE * d, long size) { - long i; - unsigned char c; - long r; - - for (i = 0; (i < size) || (size < 0); i++) { - r = fread(&c, 1, 1, s); - if (r == 0) { - break; - } - fwrite(&c, 1, 1, d); - } -} +/*
+ * PSX-Tools Bundle Pack
+ * Copyright (C) 2002 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include "generic.h"
+
+unsigned long filesize(int f_iso)
+{
+ long curpos, length;
+
+ curpos = lseek(f_iso, 0, SEEK_CUR);
+ length = lseek(f_iso, 0, SEEK_END);
+ lseek(f_iso, curpos, SEEK_SET);
+ return length;
+}
+
+void copy(int s, int d, long size) {
+ long i;
+ unsigned char c;
+ long r;
+
+ for (i = 0; (i < size) || (size < 0); i++) {
+ r = read(s, &c, 1);
+ if (r == 0) {
+ break;
+ }
+ write(d, &c, 1);
+ }
+}
+
+unsigned long filesize(FILE * f_iso)
+{
+ long curpos, length;
+
+ curpos = ftell(f_iso);
+ fseek(f_iso, 0, SEEK_END);
+ length = ftell(f_iso);
+ fseek(f_iso, curpos, SEEK_SET);
+ return length;
+}
+
+void copy(FILE * s, FILE * d, long size) {
+ long i;
+ unsigned char c;
+ long r;
+
+ for (i = 0; (i < size) || (size < 0); i++) {
+ r = fread(&c, 1, 1, s);
+ if (r == 0) {
+ break;
+ }
+ fwrite(&c, 1, 1, d);
+ }
+}
diff --git a/lib/generic.cc b/lib/generic.cc index 933f158..e641d55 100644 --- a/lib/generic.cc +++ b/lib/generic.cc @@ -1,103 +1,103 @@ -/* - * Baltisot - * Copyright (C) 1999-2003 Nicolas "Pixel" Noble - * - * 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: generic.cc,v 1.10 2004-07-23 16:56:03 pixel Exp $ */ - -#include <stdio.h> -#include <stdarg.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "BString.h" -#ifdef HAVE_GMP -#include <gmp.h> -#endif - -char verbosity = 0; -static char * heads[] = {"EE", "--", "WW", "II"}; -printer_t * printer = 0; -locker_t * locker = 0; - -void Base::printm(int level, const ugly_string & m, ...) { - va_list ap; - bool display = true; - - if (verbosity < level) { - return; - } - - va_start(ap, m); - - if (printer) - display = printer->printm(level, m.p, ap); - - if (display) { - if (level >= 0) { - fprintf(stderr, "(%s) ", heads[level]); - } - -#ifdef HAVE_GMP - gmp_vfprintf(stderr, m.p, ap); -#else - vfprintf(stderr, m.p, ap); -#endif - } - va_end(ap); -} - -void Base::printm(int level, const char * m, ...) { - va_list ap; - bool display = true; - - if (verbosity < level) { - return; - } - - va_start(ap, m); - if (printer) - display = printer->printm(level, m, ap); - - if (display) { - if (level >= 0) { - fprintf(stderr, "(%s) ", heads[level]); - } - -#ifdef HAVE_GMP - gmp_vfprintf(stderr, m, ap); -#else - vfprintf(stderr, m, ap); -#endif - } - va_end(ap); -} - -char ** split(char * s, char t) { - static char * p[100]; - int i; - - for (i = 1, p[0] = s; *s; s++) { - if (*s == t) { - *s = 0; - p[i++] = s + 1; - } - } - p[i] = 0; - - return p; -} +/*
+ * Baltisot
+ * Copyright (C) 1999-2003 Nicolas "Pixel" Noble
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* $Id: generic.cc,v 1.11 2004-11-27 21:35:19 pixel Exp $ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "BString.h"
+#ifdef HAVE_GMP
+#include <gmp.h>
+#endif
+
+char verbosity = 0;
+static char * heads[] = {"EE", "--", "WW", "II"};
+printer_t * printer = 0;
+locker_t * locker = 0;
+
+void Base::printm(int level, const ugly_string & m, ...) {
+ va_list ap;
+ bool display = true;
+
+ if (verbosity < level) {
+ return;
+ }
+
+ va_start(ap, m);
+
+ if (printer)
+ display = printer->printm(level, m.p, ap);
+
+ if (display) {
+ if (level >= 0) {
+ fprintf(stderr, "(%s) ", heads[level]);
+ }
+
+#ifdef HAVE_GMP
+ gmp_vfprintf(stderr, m.p, ap);
+#else
+ vfprintf(stderr, m.p, ap);
+#endif
+ }
+ va_end(ap);
+}
+
+void Base::printm(int level, const char * m, ...) {
+ va_list ap;
+ bool display = true;
+
+ if (verbosity < level) {
+ return;
+ }
+
+ va_start(ap, m);
+ if (printer)
+ display = printer->printm(level, m, ap);
+
+ if (display) {
+ if (level >= 0) {
+ fprintf(stderr, "(%s) ", heads[level]);
+ }
+
+#ifdef HAVE_GMP
+ gmp_vfprintf(stderr, m, ap);
+#else
+ vfprintf(stderr, m, ap);
+#endif
+ }
+ va_end(ap);
+}
+
+char ** split(char * s, char t) {
+ static char * p[100];
+ int i;
+
+ for (i = 1, p[0] = s; *s; s++) {
+ if (*s == t) {
+ *s = 0;
+ p[i++] = s + 1;
+ }
+ }
+ p[i] = 0;
+
+ return p;
+}
diff --git a/lib/lua/src/LuaLib/lauxlib.c b/lib/lua/src/LuaLib/lauxlib.c index 85b64ce..c4b24a7 100644 --- a/lib/lua/src/LuaLib/lauxlib.c +++ b/lib/lua/src/LuaLib/lauxlib.c @@ -1,591 +1,591 @@ -/* -** $Id: lauxlib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - - -#include <ctype.h> -#include <errno.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - - -/* This file uses only the official API of Lua. -** Any function declared here could be written as an application function. -*/ - -#define lauxlib_c - -#include "lua.h" - -#include "lauxlib.h" - - -/* number of prereserved references (for internal use) */ -#define RESERVED_REFS 2 - -/* reserved references */ -#define FREELIST_REF 1 /* free list of references */ -#define ARRAYSIZE_REF 2 /* array sizes */ - - -/* convert a stack index to positive */ -#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ - lua_gettop(L) + (i) + 1) - - -/* -** {====================================================== -** Error-report functions -** ======================================================= -*/ - - -LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { - lua_Debug ar; - lua_getstack(L, 0, &ar); - lua_getinfo(L, "n", &ar); - if (strcmp(ar.namewhat, "method") == 0) { - narg--; /* do not count `self' */ - if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg); - } - if (ar.name == NULL) - ar.name = "?"; - return luaL_error(L, "bad argument #%d to `%s' (%s)", - narg, ar.name, extramsg); -} - - -LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { - const char *msg = lua_pushfstring(L, "%s expected, got %s", - tname, lua_typename(L, lua_type(L,narg))); - return luaL_argerror(L, narg, msg); -} - - -static void tag_error (lua_State *L, int narg, int tag) { - luaL_typerror(L, narg, lua_typename(L, tag)); -} - - -LUALIB_API void luaL_where (lua_State *L, int level) { - lua_Debug ar; - if (lua_getstack(L, level, &ar)) { /* check function at level */ - lua_getinfo(L, "Snl", &ar); /* get info about it */ - if (ar.currentline > 0) { /* is there info? */ - lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); - return; - } - } - lua_pushliteral(L, ""); /* else, no information available... */ -} - - -LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - luaL_where(L, 1); - lua_pushvfstring(L, fmt, argp); - va_end(argp); - lua_concat(L, 2); - return lua_error(L); -} - -/* }====================================================== */ - - -LUALIB_API int luaL_findstring (const char *name, const char *const list[]) { - int i; - for (i=0; list[i]; i++) - if (strcmp(list[i], name) == 0) - return i; - return -1; /* name not found */ -} - - -LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */ - if (!lua_isnil(L, -1)) /* name already in use? */ - return 0; /* leave previous value on top, but return 0 */ - lua_pop(L, 1); - lua_newtable(L); /* create metatable */ - lua_pushstring(L, tname); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */ - lua_pushvalue(L, -1); - lua_pushstring(L, tname); - lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */ - return 1; -} - - -LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) { - lua_pushstring(L, tname); - lua_rawget(L, LUA_REGISTRYINDEX); -} - - -LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { - const char *tn; - if (!lua_getmetatable(L, ud)) return NULL; /* no metatable? */ - lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[metatable] */ - tn = lua_tostring(L, -1); - if (tn && (strcmp(tn, tname) == 0)) { - lua_pop(L, 1); - return lua_touserdata(L, ud); - } - else { - lua_pop(L, 1); - return NULL; - } -} - - -LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { - if (!lua_checkstack(L, space)) - luaL_error(L, "stack overflow (%s)", mes); -} - - -LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { - if (lua_type(L, narg) != t) - tag_error(L, narg, t); -} - - -LUALIB_API void luaL_checkany (lua_State *L, int narg) { - if (lua_type(L, narg) == LUA_TNONE) - luaL_argerror(L, narg, "value expected"); -} - - -LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { - const char *s = lua_tostring(L, narg); - if (!s) tag_error(L, narg, LUA_TSTRING); - if (len) *len = lua_strlen(L, narg); - return s; -} - - -LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, - const char *def, size_t *len) { - if (lua_isnoneornil(L, narg)) { - if (len) - *len = (def ? strlen(def) : 0); - return def; - } - else return luaL_checklstring(L, narg, len); -} - - -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { - lua_Number d = lua_tonumber(L, narg); - if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ - tag_error(L, narg, LUA_TNUMBER); - return d; -} - - -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { - if (lua_isnoneornil(L, narg)) return def; - else return luaL_checknumber(L, narg); -} - - -LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { - if (!lua_getmetatable(L, obj)) /* no metatable? */ - return 0; - lua_pushstring(L, event); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - lua_pop(L, 2); /* remove metatable and metafield */ - return 0; - } - else { - lua_remove(L, -2); /* remove only metatable */ - return 1; - } -} - - -LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { - obj = abs_index(L, obj); - if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ - return 0; - lua_pushvalue(L, obj); - lua_call(L, 1, 1); - return 1; -} - - -LUALIB_API void luaL_openlib (lua_State *L, const char *libname, - const luaL_reg *l, int nup) { - if (libname) { - lua_pushstring(L, libname); - lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */ - if (lua_isnil(L, -1)) { /* no? */ - lua_pop(L, 1); - lua_newtable(L); /* create it */ - lua_pushstring(L, libname); - lua_pushvalue(L, -2); - lua_settable(L, LUA_GLOBALSINDEX); /* register it with given name */ - } - lua_insert(L, -(nup+1)); /* move library table to below upvalues */ - } - for (; l->name; l++) { - int i; - lua_pushstring(L, l->name); - for (i=0; i<nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -(nup+1)); - lua_pushcclosure(L, l->func, nup); - lua_settable(L, -(nup+3)); - } - lua_pop(L, nup); /* remove upvalues */ -} - - - -/* -** {====================================================== -** getn-setn: size for arrays -** ======================================================= -*/ - -static int checkint (lua_State *L, int topop) { - int n = (int)lua_tonumber(L, -1); - if (n == 0 && !lua_isnumber(L, -1)) n = -1; - lua_pop(L, topop); - return n; -} - - -static void getsizes (lua_State *L) { - lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); - if (lua_isnil(L, -1)) { /* no `size' table? */ - lua_pop(L, 1); /* remove nil */ - lua_newtable(L); /* create it */ - lua_pushvalue(L, -1); /* `size' will be its own metatable */ - lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(N).__mode = "k" */ - lua_pushvalue(L, -1); - lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */ - } -} - - -void luaL_setn (lua_State *L, int t, int n) { - t = abs_index(L, t); - lua_pushliteral(L, "n"); - lua_rawget(L, t); - if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */ - lua_pushliteral(L, "n"); /* use it */ - lua_pushnumber(L, (lua_Number)n); - lua_rawset(L, t); - } - else { /* use `sizes' */ - getsizes(L); - lua_pushvalue(L, t); - lua_pushnumber(L, (lua_Number)n); - lua_rawset(L, -3); /* sizes[t] = n */ - lua_pop(L, 1); /* remove `sizes' */ - } -} - - -int luaL_getn (lua_State *L, int t) { - int n; - t = abs_index(L, t); - lua_pushliteral(L, "n"); /* try t.n */ - lua_rawget(L, t); - if ((n = checkint(L, 1)) >= 0) return n; - getsizes(L); /* else try sizes[t] */ - lua_pushvalue(L, t); - lua_rawget(L, -2); - if ((n = checkint(L, 2)) >= 0) return n; - for (n = 1; ; n++) { /* else must count elements */ - lua_rawgeti(L, t, n); - if (lua_isnil(L, -1)) break; - lua_pop(L, 1); - } - lua_pop(L, 1); - return n - 1; -} - -/* }====================================================== */ - - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - - -#define bufflen(B) ((B)->p - (B)->buffer) -#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) - -#define LIMIT (LUA_MINSTACK/2) - - -static int emptybuffer (luaL_Buffer *B) { - size_t l = bufflen(B); - if (l == 0) return 0; /* put nothing on stack */ - else { - lua_pushlstring(B->L, B->buffer, l); - B->p = B->buffer; - B->lvl++; - return 1; - } -} - - -static void adjuststack (luaL_Buffer *B) { - if (B->lvl > 1) { - lua_State *L = B->L; - int toget = 1; /* number of levels to concat */ - size_t toplen = lua_strlen(L, -1); - do { - size_t l = lua_strlen(L, -(toget+1)); - if (B->lvl - toget + 1 >= LIMIT || toplen > l) { - toplen += l; - toget++; - } - else break; - } while (toget < B->lvl); - lua_concat(L, toget); - B->lvl = B->lvl - toget + 1; - } -} - - -LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { - if (emptybuffer(B)) - adjuststack(B); - return B->buffer; -} - - -LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - while (l--) - luaL_putchar(B, *s++); -} - - -LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { - luaL_addlstring(B, s, strlen(s)); -} - - -LUALIB_API void luaL_pushresult (luaL_Buffer *B) { - emptybuffer(B); - lua_concat(B->L, B->lvl); - B->lvl = 1; -} - - -LUALIB_API void luaL_addvalue (luaL_Buffer *B) { - lua_State *L = B->L; - size_t vl = lua_strlen(L, -1); - if (vl <= bufffree(B)) { /* fit into buffer? */ - memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */ - B->p += vl; - lua_pop(L, 1); /* remove from stack */ - } - else { - if (emptybuffer(B)) - lua_insert(L, -2); /* put buffer before new value */ - B->lvl++; /* add new value into B stack */ - adjuststack(B); - } -} - - -LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { - B->L = L; - B->p = B->buffer; - B->lvl = 0; -} - -/* }====================================================== */ - - -LUALIB_API int luaL_ref (lua_State *L, int t) { - int ref; - t = abs_index(L, t); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* `nil' has a unique fixed reference */ - } - lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ - ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */ - lua_pop(L, 1); /* remove it from stack */ - if (ref != 0) { /* any free element? */ - lua_rawgeti(L, t, ref); /* remove it from list */ - lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ - } - else { /* no free elements */ - ref = luaL_getn(L, t); - if (ref < RESERVED_REFS) - ref = RESERVED_REFS; /* skip reserved references */ - ref++; /* create new reference */ - luaL_setn(L, t, ref); - } - lua_rawseti(L, t, ref); - return ref; -} - - -LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { - if (ref >= 0) { - t = abs_index(L, t); - lua_rawgeti(L, t, FREELIST_REF); - lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */ - lua_pushnumber(L, (lua_Number)ref); - lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ - } -} - - - -/* -** {====================================================== -** Load functions -** ======================================================= -*/ - -typedef struct LoadF { - FILE *f; - char buff[LUAL_BUFFERSIZE]; -} LoadF; - - -static const char *getF (lua_State *L, void *ud, size_t *size) { - LoadF *lf = (LoadF *)ud; - (void)L; - if (feof(lf->f)) return NULL; - *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f); - return (*size > 0) ? lf->buff : NULL; -} - - -static int errfile (lua_State *L, int fnameindex) { - const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno)); - lua_remove(L, fnameindex); - return LUA_ERRFILE; -} - - -LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) { - LoadF lf; - int status, readstatus; - int c; - int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - if (filename == NULL) { - lua_pushliteral(L, "=stdin"); - lf.f = stdin; - } - else { - lua_pushfstring(L, "@%s", filename); - lf.f = fopen(filename, "r"); - } - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */ - c = ungetc(getc(lf.f), lf.f); - if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */ - fclose(lf.f); - lf.f = fopen(filename, "rb"); /* reopen in binary mode */ - if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */ - } - status = lua_load(L, getF, &lf, lua_tostring(L, -1)); - readstatus = ferror(lf.f); - if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */ - if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from `lua_load' */ - return errfile(L, fnameindex); - } - lua_remove(L, fnameindex); - return status; -} - - -typedef struct LoadS { - const char *s; - size_t size; -} LoadS; - - -static const char *getS (lua_State *L, void *ud, size_t *size) { - LoadS *ls = (LoadS *)ud; - (void)L; - if (ls->size == 0) return NULL; - *size = ls->size; - ls->size = 0; - return ls->s; -} - - -LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, - const char *name) { - LoadS ls; - ls.s = buff; - ls.size = size; - return lua_load(L, getS, &ls, name); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** compatibility code -** ======================================================= -*/ - - -static void callalert (lua_State *L, int status) { - if (status != 0) { - lua_getglobal(L, "_ALERT"); - if (lua_isfunction(L, -1)) { - lua_insert(L, -2); - lua_call(L, 1, 0); - } - else { /* no _ALERT function; print it on stderr */ - fprintf(stderr, "%s\n", lua_tostring(L, -2)); - lua_pop(L, 2); /* remove error message and _ALERT */ - } - } -} - - -static int aux_do (lua_State *L, int status) { - if (status == 0) { /* parse OK? */ - status = lua_pcall(L, 0, LUA_MULTRET, 0); /* call main */ - } - callalert(L, status); - return status; -} - - -LUALIB_API int lua_dofile (lua_State *L, const char *filename) { - return aux_do(L, luaL_loadfile(L, filename)); -} - - -LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, - const char *name) { - return aux_do(L, luaL_loadbuffer(L, buff, size, name)); -} - - -LUALIB_API int lua_dostring (lua_State *L, const char *str) { - return lua_dobuffer(L, str, strlen(str), str); -} - -/* }====================================================== */ +/*
+** $Id: lauxlib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+/* This file uses only the official API of Lua.
+** Any function declared here could be written as an application function.
+*/
+
+#define lauxlib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+
+
+/* number of prereserved references (for internal use) */
+#define RESERVED_REFS 2
+
+/* reserved references */
+#define FREELIST_REF 1 /* free list of references */
+#define ARRAYSIZE_REF 2 /* array sizes */
+
+
+/* convert a stack index to positive */
+#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
+ lua_gettop(L) + (i) + 1)
+
+
+/*
+** {======================================================
+** Error-report functions
+** =======================================================
+*/
+
+
+LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
+ lua_Debug ar;
+ lua_getstack(L, 0, &ar);
+ lua_getinfo(L, "n", &ar);
+ if (strcmp(ar.namewhat, "method") == 0) {
+ narg--; /* do not count `self' */
+ if (narg == 0) /* error is in the self argument itself? */
+ return luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg);
+ }
+ if (ar.name == NULL)
+ ar.name = "?";
+ return luaL_error(L, "bad argument #%d to `%s' (%s)",
+ narg, ar.name, extramsg);
+}
+
+
+LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) {
+ const char *msg = lua_pushfstring(L, "%s expected, got %s",
+ tname, lua_typename(L, lua_type(L,narg)));
+ return luaL_argerror(L, narg, msg);
+}
+
+
+static void tag_error (lua_State *L, int narg, int tag) {
+ luaL_typerror(L, narg, lua_typename(L, tag));
+}
+
+
+LUALIB_API void luaL_where (lua_State *L, int level) {
+ lua_Debug ar;
+ if (lua_getstack(L, level, &ar)) { /* check function at level */
+ lua_getinfo(L, "Snl", &ar); /* get info about it */
+ if (ar.currentline > 0) { /* is there info? */
+ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
+ return;
+ }
+ }
+ lua_pushliteral(L, ""); /* else, no information available... */
+}
+
+
+LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ luaL_where(L, 1);
+ lua_pushvfstring(L, fmt, argp);
+ va_end(argp);
+ lua_concat(L, 2);
+ return lua_error(L);
+}
+
+/* }====================================================== */
+
+
+LUALIB_API int luaL_findstring (const char *name, const char *const list[]) {
+ int i;
+ for (i=0; list[i]; i++)
+ if (strcmp(list[i], name) == 0)
+ return i;
+ return -1; /* name not found */
+}
+
+
+LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
+ lua_pushstring(L, tname);
+ lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */
+ if (!lua_isnil(L, -1)) /* name already in use? */
+ return 0; /* leave previous value on top, but return 0 */
+ lua_pop(L, 1);
+ lua_newtable(L); /* create metatable */
+ lua_pushstring(L, tname);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */
+ lua_pushvalue(L, -1);
+ lua_pushstring(L, tname);
+ lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */
+ return 1;
+}
+
+
+LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) {
+ lua_pushstring(L, tname);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+}
+
+
+LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
+ const char *tn;
+ if (!lua_getmetatable(L, ud)) return NULL; /* no metatable? */
+ lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[metatable] */
+ tn = lua_tostring(L, -1);
+ if (tn && (strcmp(tn, tname) == 0)) {
+ lua_pop(L, 1);
+ return lua_touserdata(L, ud);
+ }
+ else {
+ lua_pop(L, 1);
+ return NULL;
+ }
+}
+
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
+ if (!lua_checkstack(L, space))
+ luaL_error(L, "stack overflow (%s)", mes);
+}
+
+
+LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
+ if (lua_type(L, narg) != t)
+ tag_error(L, narg, t);
+}
+
+
+LUALIB_API void luaL_checkany (lua_State *L, int narg) {
+ if (lua_type(L, narg) == LUA_TNONE)
+ luaL_argerror(L, narg, "value expected");
+}
+
+
+LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
+ const char *s = lua_tostring(L, narg);
+ if (!s) tag_error(L, narg, LUA_TSTRING);
+ if (len) *len = lua_strlen(L, narg);
+ return s;
+}
+
+
+LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
+ const char *def, size_t *len) {
+ if (lua_isnoneornil(L, narg)) {
+ if (len)
+ *len = (def ? strlen(def) : 0);
+ return def;
+ }
+ else return luaL_checklstring(L, narg, len);
+}
+
+
+LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
+ lua_Number d = lua_tonumber(L, narg);
+ if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
+ tag_error(L, narg, LUA_TNUMBER);
+ return d;
+}
+
+
+LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
+ if (lua_isnoneornil(L, narg)) return def;
+ else return luaL_checknumber(L, narg);
+}
+
+
+LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
+ if (!lua_getmetatable(L, obj)) /* no metatable? */
+ return 0;
+ lua_pushstring(L, event);
+ lua_rawget(L, -2);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 2); /* remove metatable and metafield */
+ return 0;
+ }
+ else {
+ lua_remove(L, -2); /* remove only metatable */
+ return 1;
+ }
+}
+
+
+LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
+ obj = abs_index(L, obj);
+ if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
+ return 0;
+ lua_pushvalue(L, obj);
+ lua_call(L, 1, 1);
+ return 1;
+}
+
+
+LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
+ const luaL_reg *l, int nup) {
+ if (libname) {
+ lua_pushstring(L, libname);
+ lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */
+ if (lua_isnil(L, -1)) { /* no? */
+ lua_pop(L, 1);
+ lua_newtable(L); /* create it */
+ lua_pushstring(L, libname);
+ lua_pushvalue(L, -2);
+ lua_settable(L, LUA_GLOBALSINDEX); /* register it with given name */
+ }
+ lua_insert(L, -(nup+1)); /* move library table to below upvalues */
+ }
+ for (; l->name; l++) {
+ int i;
+ lua_pushstring(L, l->name);
+ for (i=0; i<nup; i++) /* copy upvalues to the top */
+ lua_pushvalue(L, -(nup+1));
+ lua_pushcclosure(L, l->func, nup);
+ lua_settable(L, -(nup+3));
+ }
+ lua_pop(L, nup); /* remove upvalues */
+}
+
+
+
+/*
+** {======================================================
+** getn-setn: size for arrays
+** =======================================================
+*/
+
+static int checkint (lua_State *L, int topop) {
+ int n = (int)lua_tonumber(L, -1);
+ if (n == 0 && !lua_isnumber(L, -1)) n = -1;
+ lua_pop(L, topop);
+ return n;
+}
+
+
+static void getsizes (lua_State *L) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF);
+ if (lua_isnil(L, -1)) { /* no `size' table? */
+ lua_pop(L, 1); /* remove nil */
+ lua_newtable(L); /* create it */
+ lua_pushvalue(L, -1); /* `size' will be its own metatable */
+ lua_setmetatable(L, -2);
+ lua_pushliteral(L, "__mode");
+ lua_pushliteral(L, "k");
+ lua_rawset(L, -3); /* metatable(N).__mode = "k" */
+ lua_pushvalue(L, -1);
+ lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */
+ }
+}
+
+
+void luaL_setn (lua_State *L, int t, int n) {
+ t = abs_index(L, t);
+ lua_pushliteral(L, "n");
+ lua_rawget(L, t);
+ if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */
+ lua_pushliteral(L, "n"); /* use it */
+ lua_pushnumber(L, (lua_Number)n);
+ lua_rawset(L, t);
+ }
+ else { /* use `sizes' */
+ getsizes(L);
+ lua_pushvalue(L, t);
+ lua_pushnumber(L, (lua_Number)n);
+ lua_rawset(L, -3); /* sizes[t] = n */
+ lua_pop(L, 1); /* remove `sizes' */
+ }
+}
+
+
+int luaL_getn (lua_State *L, int t) {
+ int n;
+ t = abs_index(L, t);
+ lua_pushliteral(L, "n"); /* try t.n */
+ lua_rawget(L, t);
+ if ((n = checkint(L, 1)) >= 0) return n;
+ getsizes(L); /* else try sizes[t] */
+ lua_pushvalue(L, t);
+ lua_rawget(L, -2);
+ if ((n = checkint(L, 2)) >= 0) return n;
+ for (n = 1; ; n++) { /* else must count elements */
+ lua_rawgeti(L, t, n);
+ if (lua_isnil(L, -1)) break;
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+ return n - 1;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+#define bufflen(B) ((B)->p - (B)->buffer)
+#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
+
+#define LIMIT (LUA_MINSTACK/2)
+
+
+static int emptybuffer (luaL_Buffer *B) {
+ size_t l = bufflen(B);
+ if (l == 0) return 0; /* put nothing on stack */
+ else {
+ lua_pushlstring(B->L, B->buffer, l);
+ B->p = B->buffer;
+ B->lvl++;
+ return 1;
+ }
+}
+
+
+static void adjuststack (luaL_Buffer *B) {
+ if (B->lvl > 1) {
+ lua_State *L = B->L;
+ int toget = 1; /* number of levels to concat */
+ size_t toplen = lua_strlen(L, -1);
+ do {
+ size_t l = lua_strlen(L, -(toget+1));
+ if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
+ toplen += l;
+ toget++;
+ }
+ else break;
+ } while (toget < B->lvl);
+ lua_concat(L, toget);
+ B->lvl = B->lvl - toget + 1;
+ }
+}
+
+
+LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
+ if (emptybuffer(B))
+ adjuststack(B);
+ return B->buffer;
+}
+
+
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
+ while (l--)
+ luaL_putchar(B, *s++);
+}
+
+
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
+ luaL_addlstring(B, s, strlen(s));
+}
+
+
+LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
+ emptybuffer(B);
+ lua_concat(B->L, B->lvl);
+ B->lvl = 1;
+}
+
+
+LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
+ lua_State *L = B->L;
+ size_t vl = lua_strlen(L, -1);
+ if (vl <= bufffree(B)) { /* fit into buffer? */
+ memcpy(B->p, lua_tostring(L, -1), vl); /* put it there */
+ B->p += vl;
+ lua_pop(L, 1); /* remove from stack */
+ }
+ else {
+ if (emptybuffer(B))
+ lua_insert(L, -2); /* put buffer before new value */
+ B->lvl++; /* add new value into B stack */
+ adjuststack(B);
+ }
+}
+
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
+ B->L = L;
+ B->p = B->buffer;
+ B->lvl = 0;
+}
+
+/* }====================================================== */
+
+
+LUALIB_API int luaL_ref (lua_State *L, int t) {
+ int ref;
+ t = abs_index(L, t);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1); /* remove from stack */
+ return LUA_REFNIL; /* `nil' has a unique fixed reference */
+ }
+ lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
+ ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */
+ lua_pop(L, 1); /* remove it from stack */
+ if (ref != 0) { /* any free element? */
+ lua_rawgeti(L, t, ref); /* remove it from list */
+ lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
+ }
+ else { /* no free elements */
+ ref = luaL_getn(L, t);
+ if (ref < RESERVED_REFS)
+ ref = RESERVED_REFS; /* skip reserved references */
+ ref++; /* create new reference */
+ luaL_setn(L, t, ref);
+ }
+ lua_rawseti(L, t, ref);
+ return ref;
+}
+
+
+LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
+ if (ref >= 0) {
+ t = abs_index(L, t);
+ lua_rawgeti(L, t, FREELIST_REF);
+ lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
+ lua_pushnumber(L, (lua_Number)ref);
+ lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
+ }
+}
+
+
+
+/*
+** {======================================================
+** Load functions
+** =======================================================
+*/
+
+typedef struct LoadF {
+ FILE *f;
+ char buff[LUAL_BUFFERSIZE];
+} LoadF;
+
+
+static const char *getF (lua_State *L, void *ud, size_t *size) {
+ LoadF *lf = (LoadF *)ud;
+ (void)L;
+ if (feof(lf->f)) return NULL;
+ *size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f);
+ return (*size > 0) ? lf->buff : NULL;
+}
+
+
+static int errfile (lua_State *L, int fnameindex) {
+ const char *filename = lua_tostring(L, fnameindex) + 1;
+ lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno));
+ lua_remove(L, fnameindex);
+ return LUA_ERRFILE;
+}
+
+
+LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
+ LoadF lf;
+ int status, readstatus;
+ int c;
+ int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
+ if (filename == NULL) {
+ lua_pushliteral(L, "=stdin");
+ lf.f = stdin;
+ }
+ else {
+ lua_pushfstring(L, "@%s", filename);
+ lf.f = fopen(filename, "r");
+ }
+ if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */
+ c = ungetc(getc(lf.f), lf.f);
+ if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */
+ fclose(lf.f);
+ lf.f = fopen(filename, "rb"); /* reopen in binary mode */
+ if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */
+ }
+ status = lua_load(L, getF, &lf, lua_tostring(L, -1));
+ readstatus = ferror(lf.f);
+ if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */
+ if (readstatus) {
+ lua_settop(L, fnameindex); /* ignore results from `lua_load' */
+ return errfile(L, fnameindex);
+ }
+ lua_remove(L, fnameindex);
+ return status;
+}
+
+
+typedef struct LoadS {
+ const char *s;
+ size_t size;
+} LoadS;
+
+
+static const char *getS (lua_State *L, void *ud, size_t *size) {
+ LoadS *ls = (LoadS *)ud;
+ (void)L;
+ if (ls->size == 0) return NULL;
+ *size = ls->size;
+ ls->size = 0;
+ return ls->s;
+}
+
+
+LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,
+ const char *name) {
+ LoadS ls;
+ ls.s = buff;
+ ls.size = size;
+ return lua_load(L, getS, &ls, name);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** compatibility code
+** =======================================================
+*/
+
+
+static void callalert (lua_State *L, int status) {
+ if (status != 0) {
+ lua_getglobal(L, "_ALERT");
+ if (lua_isfunction(L, -1)) {
+ lua_insert(L, -2);
+ lua_call(L, 1, 0);
+ }
+ else { /* no _ALERT function; print it on stderr */
+ fprintf(stderr, "%s\n", lua_tostring(L, -2));
+ lua_pop(L, 2); /* remove error message and _ALERT */
+ }
+ }
+}
+
+
+static int aux_do (lua_State *L, int status) {
+ if (status == 0) { /* parse OK? */
+ status = lua_pcall(L, 0, LUA_MULTRET, 0); /* call main */
+ }
+ callalert(L, status);
+ return status;
+}
+
+
+LUALIB_API int lua_dofile (lua_State *L, const char *filename) {
+ return aux_do(L, luaL_loadfile(L, filename));
+}
+
+
+LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t size,
+ const char *name) {
+ return aux_do(L, luaL_loadbuffer(L, buff, size, name));
+}
+
+
+LUALIB_API int lua_dostring (lua_State *L, const char *str) {
+ return lua_dobuffer(L, str, strlen(str), str);
+}
+
+/* }====================================================== */
diff --git a/lib/lua/src/LuaLib/lbaselib.c b/lib/lua/src/LuaLib/lbaselib.c index 5a3245a..6c928b5 100644 --- a/lib/lua/src/LuaLib/lbaselib.c +++ b/lib/lua/src/LuaLib/lbaselib.c @@ -1,674 +1,674 @@ -/* -** $Id: lbaselib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Basic library -** See Copyright Notice in lua.h -*/ - - - -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define lbaselib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - - - -/* -** If your system does not support `stdout', you can just remove this function. -** If you need, you can define your own `print' function, following this -** model but changing `fputs' to put the strings at a proper place -** (a console window or a log file, for instance). -*/ -static int luaB_print (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int i; - lua_getglobal(L, "tostring"); - for (i=1; i<=n; i++) { - const char *s; - lua_pushvalue(L, -1); /* function to be called */ - lua_pushvalue(L, i); /* value to print */ - lua_call(L, 1, 1); - s = lua_tostring(L, -1); /* get result */ - if (s == NULL) - return luaL_error(L, "`tostring' must return a string to `print'"); - if (i>1) fputs("\t", stdout); - fputs(s, stdout); - lua_pop(L, 1); /* pop result */ - } - fputs("\n", stdout); - return 0; -} - - -static int luaB_tonumber (lua_State *L) { - int base = luaL_optint(L, 2, 10); - if (base == 10) { /* standard conversion */ - luaL_checkany(L, 1); - if (lua_isnumber(L, 1)) { - lua_pushnumber(L, lua_tonumber(L, 1)); - return 1; - } - } - else { - const char *s1 = luaL_checkstring(L, 1); - char *s2; - unsigned long n; - luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - n = strtoul(s1, &s2, base); - if (s1 != s2) { /* at least one valid digit? */ - while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */ - if (*s2 == '\0') { /* no invalid trailing characters? */ - lua_pushnumber(L, (lua_Number)n); - return 1; - } - } - } - lua_pushnil(L); /* else not a number */ - return 1; -} - - -static int luaB_error (lua_State *L) { - int level = luaL_optint(L, 2, 1); - luaL_checkany(L, 1); - if (!lua_isstring(L, 1) || level == 0) - lua_pushvalue(L, 1); /* propagate error message without changes */ - else { /* add extra information */ - luaL_where(L, level); - lua_pushvalue(L, 1); - lua_concat(L, 2); - } - return lua_error(L); -} - - -static int luaB_getmetatable (lua_State *L) { - luaL_checkany(L, 1); - if (!lua_getmetatable(L, 1)) { - lua_pushnil(L); - return 1; /* no metatable */ - } - luaL_getmetafield(L, 1, "__metatable"); - return 1; /* returns either __metatable field (if present) or metatable */ -} - - -static int luaB_setmetatable (lua_State *L) { - int t = lua_type(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - if (luaL_getmetafield(L, 1, "__metatable")) - luaL_error(L, "cannot change a protected metatable"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; -} - - -static void getfunc (lua_State *L) { - if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); - else { - lua_Debug ar; - int level = luaL_optint(L, 1, 1); - luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); - if (lua_getstack(L, level, &ar) == 0) - luaL_argerror(L, 1, "invalid level"); - lua_getinfo(L, "f", &ar); - if (lua_isnil(L, -1)) - luaL_error(L, "no function environment for tail call at level %d", - level); - } -} - - -static int aux_getfenv (lua_State *L) { - lua_getfenv(L, -1); - lua_pushliteral(L, "__fenv"); - lua_rawget(L, -2); - return !lua_isnil(L, -1); -} - - -static int luaB_getfenv (lua_State *L) { - getfunc(L); - if (!aux_getfenv(L)) /* __fenv not defined? */ - lua_pop(L, 1); /* remove it, to return real environment */ - return 1; -} - - -static int luaB_setfenv (lua_State *L) { - luaL_checktype(L, 2, LUA_TTABLE); - getfunc(L); - if (aux_getfenv(L)) /* __fenv defined? */ - luaL_error(L, "`setfenv' cannot change a protected environment"); - else - lua_pop(L, 2); /* remove __fenv and real environment table */ - lua_pushvalue(L, 2); - if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) - lua_replace(L, LUA_GLOBALSINDEX); - else if (lua_setfenv(L, -2) == 0) - luaL_error(L, "`setfenv' cannot change environment of given function"); - return 0; -} - - -static int luaB_rawequal (lua_State *L) { - luaL_checkany(L, 1); - luaL_checkany(L, 2); - lua_pushboolean(L, lua_rawequal(L, 1, 2)); - return 1; -} - - -static int luaB_rawget (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - lua_rawget(L, 1); - return 1; -} - -static int luaB_rawset (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - luaL_checkany(L, 3); - lua_rawset(L, 1); - return 1; -} - - -static int luaB_gcinfo (lua_State *L) { - lua_pushnumber(L, (lua_Number)lua_getgccount(L)); - lua_pushnumber(L, (lua_Number)lua_getgcthreshold(L)); - return 2; -} - - -static int luaB_collectgarbage (lua_State *L) { - lua_setgcthreshold(L, luaL_optint(L, 1, 0)); - return 0; -} - - -static int luaB_type (lua_State *L) { - luaL_checkany(L, 1); - lua_pushstring(L, lua_typename(L, lua_type(L, 1))); - return 1; -} - - -static int luaB_next (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 2); /* create a 2nd argument if there isn't one */ - if (lua_next(L, 1)) - return 2; - else { - lua_pushnil(L); - return 1; - } -} - - -static int luaB_pairs (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushliteral(L, "next"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushnil(L); /* and initial value */ - return 3; -} - - -static int luaB_ipairs (lua_State *L) { - lua_Number i = lua_tonumber(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */ - lua_pushliteral(L, "ipairs"); - lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushnumber(L, 0); /* and initial value */ - return 3; - } - else { /* `for' step */ - i++; /* next value */ - lua_pushnumber(L, i); - lua_rawgeti(L, 1, (int)i); - return (lua_isnil(L, -1)) ? 0 : 2; - } -} - - -static int load_aux (lua_State *L, int status) { - if (status == 0) /* OK? */ - return 1; - else { - lua_pushnil(L); - lua_insert(L, -2); /* put before error message */ - return 2; /* return nil plus error message */ - } -} - - -static int luaB_loadstring (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - const char *chunkname = luaL_optstring(L, 2, s); - return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); -} - - -static int luaB_loadfile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - return load_aux(L, luaL_loadfile(L, fname)); -} - - -static int luaB_dofile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - int status = luaL_loadfile(L, fname); - if (status != 0) lua_error(L); - lua_call(L, 0, LUA_MULTRET); - return lua_gettop(L) - 1; -} - - -static int luaB_assert (lua_State *L) { - luaL_checkany(L, 1); - if (!lua_toboolean(L, 1)) - return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); - lua_settop(L, 1); - return 1; -} - - -static int luaB_unpack (lua_State *L) { - int n, i; - luaL_checktype(L, 1, LUA_TTABLE); - n = luaL_getn(L, 1); - luaL_checkstack(L, n, "table too big to unpack"); - for (i=1; i<=n; i++) /* push arg[1...n] */ - lua_rawgeti(L, 1, i); - return n; -} - - -static int luaB_pcall (lua_State *L) { - int status; - luaL_checkany(L, 1); - status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); - lua_pushboolean(L, (status == 0)); - lua_insert(L, 1); - return lua_gettop(L); /* return status + all results */ -} - - -static int luaB_xpcall (lua_State *L) { - int status; - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_insert(L, 1); /* put error function under function to be called */ - status = lua_pcall(L, 0, LUA_MULTRET, 1); - lua_pushboolean(L, (status == 0)); - lua_replace(L, 1); - return lua_gettop(L); /* return status + all results */ -} - - -static int luaB_tostring (lua_State *L) { - char buff[64]; - luaL_checkany(L, 1); - if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ - return 1; /* use its value */ - switch (lua_type(L, 1)) { - case LUA_TNUMBER: - lua_pushstring(L, lua_tostring(L, 1)); - return 1; - case LUA_TSTRING: - lua_pushvalue(L, 1); - return 1; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false")); - return 1; - case LUA_TTABLE: - sprintf(buff, "table: %p", lua_topointer(L, 1)); - break; - case LUA_TFUNCTION: - sprintf(buff, "function: %p", lua_topointer(L, 1)); - break; - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - sprintf(buff, "userdata: %p", lua_touserdata(L, 1)); - break; - case LUA_TTHREAD: - sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1)); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - return 1; - } - lua_pushstring(L, buff); - return 1; -} - - -static int luaB_newproxy (lua_State *L) { - lua_settop(L, 1); - lua_newuserdata(L, 0); /* create proxy */ - if (lua_toboolean(L, 1) == 0) - return 1; /* no metatable */ - else if (lua_isboolean(L, 1)) { - lua_newtable(L); /* create a new metatable `m' ... */ - lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ - lua_pushboolean(L, 1); - lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ - } - else { - int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ - if (lua_getmetatable(L, 1)) { - lua_rawget(L, lua_upvalueindex(1)); - validproxy = lua_toboolean(L, -1); - lua_pop(L, 1); /* remove value */ - } - luaL_argcheck(L, validproxy, 1, "boolean or proxy expected"); - lua_getmetatable(L, 1); /* metatable is valid; get it */ - } - lua_setmetatable(L, 2); - return 1; -} - - -/* -** {====================================================== -** `require' function -** ======================================================= -*/ - - -/* name of global that holds table with loaded packages */ -#define REQTAB "_LOADED" - -/* name of global that holds the search path for packages */ -#define LUA_PATH "LUA_PATH" - -#ifndef LUA_PATH_SEP -#define LUA_PATH_SEP ';' -#endif - -#ifndef LUA_PATH_MARK -#define LUA_PATH_MARK '?' -#endif - -#ifndef LUA_PATH_DEFAULT -#define LUA_PATH_DEFAULT "?;?.lua" -#endif - - -static const char *getpath (lua_State *L) { - const char *path; - lua_getglobal(L, LUA_PATH); /* try global variable */ - path = lua_tostring(L, -1); - lua_pop(L, 1); - if (path) return path; - path = getenv(LUA_PATH); /* else try environment variable */ - if (path) return path; - return LUA_PATH_DEFAULT; /* else use default */ -} - - -static const char *pushnextpath (lua_State *L, const char *path) { - const char *l; - if (*path == '\0') return NULL; /* no more paths */ - if (*path == LUA_PATH_SEP) path++; /* skip separator */ - l = strchr(path, LUA_PATH_SEP); /* find next separator */ - if (l == NULL) l = path+strlen(path); - lua_pushlstring(L, path, l - path); /* directory name */ - return l; -} - - -static void pushcomposename (lua_State *L) { - const char *path = lua_tostring(L, -1); - const char *wild; - int n = 1; - while ((wild = strchr(path, LUA_PATH_MARK)) != NULL) { - /* is there stack space for prefix, name, and eventual last sufix? */ - luaL_checkstack(L, 3, "too many marks in a path component"); - lua_pushlstring(L, path, wild - path); /* push prefix */ - lua_pushvalue(L, 1); /* push package name (in place of MARK) */ - path = wild + 1; /* continue after MARK */ - n += 2; - } - lua_pushstring(L, path); /* push last sufix (`n' already includes this) */ - lua_concat(L, n); -} - - -static int luaB_require (lua_State *L) { - const char *path; - int status = LUA_ERRFILE; /* not found (yet) */ - luaL_checkstring(L, 1); - lua_settop(L, 1); - lua_getglobal(L, REQTAB); - if (!lua_istable(L, 2)) return luaL_error(L, "`" REQTAB "' is not a table"); - path = getpath(L); - lua_pushvalue(L, 1); /* check package's name in book-keeping table */ - lua_rawget(L, 2); - if (lua_toboolean(L, -1)) /* is it there? */ - return 1; /* package is already loaded; return its result */ - else { /* must load it */ - while (status == LUA_ERRFILE) { - lua_settop(L, 3); /* reset stack position */ - if ((path = pushnextpath(L, path)) == NULL) break; - pushcomposename(L); - status = luaL_loadfile(L, lua_tostring(L, -1)); /* try to load it */ - } - } - switch (status) { - case 0: { - lua_getglobal(L, "_REQUIREDNAME"); /* save previous name */ - lua_insert(L, -2); /* put it below function */ - lua_pushvalue(L, 1); - lua_setglobal(L, "_REQUIREDNAME"); /* set new name */ - lua_call(L, 0, 1); /* run loaded module */ - lua_insert(L, -2); /* put result below previous name */ - lua_setglobal(L, "_REQUIREDNAME"); /* reset to previous name */ - if (lua_isnil(L, -1)) { /* no/nil return? */ - lua_pushboolean(L, 1); - lua_replace(L, -2); /* replace to true */ - } - lua_pushvalue(L, 1); - lua_pushvalue(L, -2); - lua_rawset(L, 2); /* mark it as loaded */ - return 1; /* return value */ - } - case LUA_ERRFILE: { /* file not found */ - return luaL_error(L, "could not load package `%s' from path `%s'", - lua_tostring(L, 1), getpath(L)); - } - default: { - return luaL_error(L, "error loading package `%s' (%s)", - lua_tostring(L, 1), lua_tostring(L, -1)); - } - } -} - -/* }====================================================== */ - - -static const luaL_reg base_funcs[] = { - {"error", luaB_error}, - {"getmetatable", luaB_getmetatable}, - {"setmetatable", luaB_setmetatable}, - {"getfenv", luaB_getfenv}, - {"setfenv", luaB_setfenv}, - {"next", luaB_next}, - {"ipairs", luaB_ipairs}, - {"pairs", luaB_pairs}, - {"print", luaB_print}, - {"tonumber", luaB_tonumber}, - {"tostring", luaB_tostring}, - {"type", luaB_type}, - {"assert", luaB_assert}, - {"unpack", luaB_unpack}, - {"rawequal", luaB_rawequal}, - {"rawget", luaB_rawget}, - {"rawset", luaB_rawset}, - {"pcall", luaB_pcall}, - {"xpcall", luaB_xpcall}, - {"collectgarbage", luaB_collectgarbage}, - {"gcinfo", luaB_gcinfo}, - {"loadfile", luaB_loadfile}, - {"dofile", luaB_dofile}, - {"loadstring", luaB_loadstring}, - {"require", luaB_require}, - {NULL, NULL} -}; - - -/* -** {====================================================== -** Coroutine library -** ======================================================= -*/ - -static int auxresume (lua_State *L, lua_State *co, int narg) { - int status; - if (!lua_checkstack(co, narg)) - luaL_error(L, "too many arguments to resume"); - lua_xmove(L, co, narg); - status = lua_resume(co, narg); - if (status == 0) { - int nres = lua_gettop(co); - if (!lua_checkstack(L, nres)) - luaL_error(L, "too many results to resume"); - lua_xmove(co, L, nres); /* move yielded values */ - return nres; - } - else { - lua_xmove(co, L, 1); /* move error message */ - return -1; /* error flag */ - } -} - - -static int luaB_coresume (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - int r; - luaL_argcheck(L, co, 1, "coroutine expected"); - r = auxresume(L, co, lua_gettop(L) - 1); - if (r < 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - lua_insert(L, -(r + 1)); - return r + 1; /* return true + `resume' returns */ - } -} - - -static int luaB_auxwrap (lua_State *L) { - lua_State *co = lua_tothread(L, lua_upvalueindex(1)); - int r = auxresume(L, co, lua_gettop(L)); - if (r < 0) { - if (lua_isstring(L, -1)) { /* error object is a string? */ - luaL_where(L, 1); /* add extra info */ - lua_insert(L, -2); - lua_concat(L, 2); - } - lua_error(L); /* propagate error */ - } - return r; -} - - -static int luaB_cocreate (lua_State *L) { - lua_State *NL = lua_newthread(L); - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); - lua_pushvalue(L, 1); /* move function to top */ - lua_xmove(L, NL, 1); /* move function from L to NL */ - return 1; -} - - -static int luaB_cowrap (lua_State *L) { - luaB_cocreate(L); - lua_pushcclosure(L, luaB_auxwrap, 1); - return 1; -} - - -static int luaB_yield (lua_State *L) { - return lua_yield(L, lua_gettop(L)); -} - - -static int luaB_costatus (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - if (L == co) lua_pushliteral(L, "running"); - else { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) == 0 && lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); - } - return 1; -} - - -static const luaL_reg co_funcs[] = { - {"create", luaB_cocreate}, - {"wrap", luaB_cowrap}, - {"resume", luaB_coresume}, - {"yield", luaB_yield}, - {"status", luaB_costatus}, - {NULL, NULL} -}; - -/* }====================================================== */ - - - -static void base_open (lua_State *L) { - lua_pushliteral(L, "_G"); - lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */ - lua_pushliteral(L, "_VERSION"); - lua_pushliteral(L, LUA_VERSION); - lua_rawset(L, -3); /* set global _VERSION */ - /* `newproxy' needs a weaktable as upvalue */ - lua_pushliteral(L, "newproxy"); - lua_newtable(L); /* new table `w' */ - lua_pushvalue(L, -1); /* `w' will be its own metatable */ - lua_setmetatable(L, -2); - lua_pushliteral(L, "__mode"); - lua_pushliteral(L, "k"); - lua_rawset(L, -3); /* metatable(w).__mode = "k" */ - lua_pushcclosure(L, luaB_newproxy, 1); - lua_rawset(L, -3); /* set global `newproxy' */ - lua_rawset(L, -1); /* set global _G */ -} - - -LUALIB_API int luaopen_base (lua_State *L) { - base_open(L); - luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); - lua_newtable(L); - lua_setglobal(L, REQTAB); - return 0; -} - +/*
+** $Id: lbaselib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Basic library
+** See Copyright Notice in lua.h
+*/
+
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define lbaselib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+
+/*
+** If your system does not support `stdout', you can just remove this function.
+** If you need, you can define your own `print' function, following this
+** model but changing `fputs' to put the strings at a proper place
+** (a console window or a log file, for instance).
+*/
+static int luaB_print (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ lua_getglobal(L, "tostring");
+ for (i=1; i<=n; i++) {
+ const char *s;
+ lua_pushvalue(L, -1); /* function to be called */
+ lua_pushvalue(L, i); /* value to print */
+ lua_call(L, 1, 1);
+ s = lua_tostring(L, -1); /* get result */
+ if (s == NULL)
+ return luaL_error(L, "`tostring' must return a string to `print'");
+ if (i>1) fputs("\t", stdout);
+ fputs(s, stdout);
+ lua_pop(L, 1); /* pop result */
+ }
+ fputs("\n", stdout);
+ return 0;
+}
+
+
+static int luaB_tonumber (lua_State *L) {
+ int base = luaL_optint(L, 2, 10);
+ if (base == 10) { /* standard conversion */
+ luaL_checkany(L, 1);
+ if (lua_isnumber(L, 1)) {
+ lua_pushnumber(L, lua_tonumber(L, 1));
+ return 1;
+ }
+ }
+ else {
+ const char *s1 = luaL_checkstring(L, 1);
+ char *s2;
+ unsigned long n;
+ luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
+ n = strtoul(s1, &s2, base);
+ if (s1 != s2) { /* at least one valid digit? */
+ while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
+ if (*s2 == '\0') { /* no invalid trailing characters? */
+ lua_pushnumber(L, (lua_Number)n);
+ return 1;
+ }
+ }
+ }
+ lua_pushnil(L); /* else not a number */
+ return 1;
+}
+
+
+static int luaB_error (lua_State *L) {
+ int level = luaL_optint(L, 2, 1);
+ luaL_checkany(L, 1);
+ if (!lua_isstring(L, 1) || level == 0)
+ lua_pushvalue(L, 1); /* propagate error message without changes */
+ else { /* add extra information */
+ luaL_where(L, level);
+ lua_pushvalue(L, 1);
+ lua_concat(L, 2);
+ }
+ return lua_error(L);
+}
+
+
+static int luaB_getmetatable (lua_State *L) {
+ luaL_checkany(L, 1);
+ if (!lua_getmetatable(L, 1)) {
+ lua_pushnil(L);
+ return 1; /* no metatable */
+ }
+ luaL_getmetafield(L, 1, "__metatable");
+ return 1; /* returns either __metatable field (if present) or metatable */
+}
+
+
+static int luaB_setmetatable (lua_State *L) {
+ int t = lua_type(L, 2);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
+ "nil or table expected");
+ if (luaL_getmetafield(L, 1, "__metatable"))
+ luaL_error(L, "cannot change a protected metatable");
+ lua_settop(L, 2);
+ lua_setmetatable(L, 1);
+ return 1;
+}
+
+
+static void getfunc (lua_State *L) {
+ if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
+ else {
+ lua_Debug ar;
+ int level = luaL_optint(L, 1, 1);
+ luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
+ if (lua_getstack(L, level, &ar) == 0)
+ luaL_argerror(L, 1, "invalid level");
+ lua_getinfo(L, "f", &ar);
+ if (lua_isnil(L, -1))
+ luaL_error(L, "no function environment for tail call at level %d",
+ level);
+ }
+}
+
+
+static int aux_getfenv (lua_State *L) {
+ lua_getfenv(L, -1);
+ lua_pushliteral(L, "__fenv");
+ lua_rawget(L, -2);
+ return !lua_isnil(L, -1);
+}
+
+
+static int luaB_getfenv (lua_State *L) {
+ getfunc(L);
+ if (!aux_getfenv(L)) /* __fenv not defined? */
+ lua_pop(L, 1); /* remove it, to return real environment */
+ return 1;
+}
+
+
+static int luaB_setfenv (lua_State *L) {
+ luaL_checktype(L, 2, LUA_TTABLE);
+ getfunc(L);
+ if (aux_getfenv(L)) /* __fenv defined? */
+ luaL_error(L, "`setfenv' cannot change a protected environment");
+ else
+ lua_pop(L, 2); /* remove __fenv and real environment table */
+ lua_pushvalue(L, 2);
+ if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0)
+ lua_replace(L, LUA_GLOBALSINDEX);
+ else if (lua_setfenv(L, -2) == 0)
+ luaL_error(L, "`setfenv' cannot change environment of given function");
+ return 0;
+}
+
+
+static int luaB_rawequal (lua_State *L) {
+ luaL_checkany(L, 1);
+ luaL_checkany(L, 2);
+ lua_pushboolean(L, lua_rawequal(L, 1, 2));
+ return 1;
+}
+
+
+static int luaB_rawget (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ lua_rawget(L, 1);
+ return 1;
+}
+
+static int luaB_rawset (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checkany(L, 2);
+ luaL_checkany(L, 3);
+ lua_rawset(L, 1);
+ return 1;
+}
+
+
+static int luaB_gcinfo (lua_State *L) {
+ lua_pushnumber(L, (lua_Number)lua_getgccount(L));
+ lua_pushnumber(L, (lua_Number)lua_getgcthreshold(L));
+ return 2;
+}
+
+
+static int luaB_collectgarbage (lua_State *L) {
+ lua_setgcthreshold(L, luaL_optint(L, 1, 0));
+ return 0;
+}
+
+
+static int luaB_type (lua_State *L) {
+ luaL_checkany(L, 1);
+ lua_pushstring(L, lua_typename(L, lua_type(L, 1)));
+ return 1;
+}
+
+
+static int luaB_next (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_settop(L, 2); /* create a 2nd argument if there isn't one */
+ if (lua_next(L, 1))
+ return 2;
+ else {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+
+static int luaB_pairs (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_pushliteral(L, "next");
+ lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */
+ lua_pushvalue(L, 1); /* state, */
+ lua_pushnil(L); /* and initial value */
+ return 3;
+}
+
+
+static int luaB_ipairs (lua_State *L) {
+ lua_Number i = lua_tonumber(L, 2);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ if (i == 0 && lua_isnone(L, 2)) { /* `for' start? */
+ lua_pushliteral(L, "ipairs");
+ lua_rawget(L, LUA_GLOBALSINDEX); /* return generator, */
+ lua_pushvalue(L, 1); /* state, */
+ lua_pushnumber(L, 0); /* and initial value */
+ return 3;
+ }
+ else { /* `for' step */
+ i++; /* next value */
+ lua_pushnumber(L, i);
+ lua_rawgeti(L, 1, (int)i);
+ return (lua_isnil(L, -1)) ? 0 : 2;
+ }
+}
+
+
+static int load_aux (lua_State *L, int status) {
+ if (status == 0) /* OK? */
+ return 1;
+ else {
+ lua_pushnil(L);
+ lua_insert(L, -2); /* put before error message */
+ return 2; /* return nil plus error message */
+ }
+}
+
+
+static int luaB_loadstring (lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ const char *chunkname = luaL_optstring(L, 2, s);
+ return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
+}
+
+
+static int luaB_loadfile (lua_State *L) {
+ const char *fname = luaL_optstring(L, 1, NULL);
+ return load_aux(L, luaL_loadfile(L, fname));
+}
+
+
+static int luaB_dofile (lua_State *L) {
+ const char *fname = luaL_optstring(L, 1, NULL);
+ int status = luaL_loadfile(L, fname);
+ if (status != 0) lua_error(L);
+ lua_call(L, 0, LUA_MULTRET);
+ return lua_gettop(L) - 1;
+}
+
+
+static int luaB_assert (lua_State *L) {
+ luaL_checkany(L, 1);
+ if (!lua_toboolean(L, 1))
+ return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+static int luaB_unpack (lua_State *L) {
+ int n, i;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ n = luaL_getn(L, 1);
+ luaL_checkstack(L, n, "table too big to unpack");
+ for (i=1; i<=n; i++) /* push arg[1...n] */
+ lua_rawgeti(L, 1, i);
+ return n;
+}
+
+
+static int luaB_pcall (lua_State *L) {
+ int status;
+ luaL_checkany(L, 1);
+ status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
+ lua_pushboolean(L, (status == 0));
+ lua_insert(L, 1);
+ return lua_gettop(L); /* return status + all results */
+}
+
+
+static int luaB_xpcall (lua_State *L) {
+ int status;
+ luaL_checkany(L, 2);
+ lua_settop(L, 2);
+ lua_insert(L, 1); /* put error function under function to be called */
+ status = lua_pcall(L, 0, LUA_MULTRET, 1);
+ lua_pushboolean(L, (status == 0));
+ lua_replace(L, 1);
+ return lua_gettop(L); /* return status + all results */
+}
+
+
+static int luaB_tostring (lua_State *L) {
+ char buff[64];
+ luaL_checkany(L, 1);
+ if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */
+ return 1; /* use its value */
+ switch (lua_type(L, 1)) {
+ case LUA_TNUMBER:
+ lua_pushstring(L, lua_tostring(L, 1));
+ return 1;
+ case LUA_TSTRING:
+ lua_pushvalue(L, 1);
+ return 1;
+ case LUA_TBOOLEAN:
+ lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
+ return 1;
+ case LUA_TTABLE:
+ sprintf(buff, "table: %p", lua_topointer(L, 1));
+ break;
+ case LUA_TFUNCTION:
+ sprintf(buff, "function: %p", lua_topointer(L, 1));
+ break;
+ case LUA_TUSERDATA:
+ case LUA_TLIGHTUSERDATA:
+ sprintf(buff, "userdata: %p", lua_touserdata(L, 1));
+ break;
+ case LUA_TTHREAD:
+ sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1));
+ break;
+ case LUA_TNIL:
+ lua_pushliteral(L, "nil");
+ return 1;
+ }
+ lua_pushstring(L, buff);
+ return 1;
+}
+
+
+static int luaB_newproxy (lua_State *L) {
+ lua_settop(L, 1);
+ lua_newuserdata(L, 0); /* create proxy */
+ if (lua_toboolean(L, 1) == 0)
+ return 1; /* no metatable */
+ else if (lua_isboolean(L, 1)) {
+ lua_newtable(L); /* create a new metatable `m' ... */
+ lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */
+ lua_pushboolean(L, 1);
+ lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */
+ }
+ else {
+ int validproxy = 0; /* to check if weaktable[metatable(u)] == true */
+ if (lua_getmetatable(L, 1)) {
+ lua_rawget(L, lua_upvalueindex(1));
+ validproxy = lua_toboolean(L, -1);
+ lua_pop(L, 1); /* remove value */
+ }
+ luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
+ lua_getmetatable(L, 1); /* metatable is valid; get it */
+ }
+ lua_setmetatable(L, 2);
+ return 1;
+}
+
+
+/*
+** {======================================================
+** `require' function
+** =======================================================
+*/
+
+
+/* name of global that holds table with loaded packages */
+#define REQTAB "_LOADED"
+
+/* name of global that holds the search path for packages */
+#define LUA_PATH "LUA_PATH"
+
+#ifndef LUA_PATH_SEP
+#define LUA_PATH_SEP ';'
+#endif
+
+#ifndef LUA_PATH_MARK
+#define LUA_PATH_MARK '?'
+#endif
+
+#ifndef LUA_PATH_DEFAULT
+#define LUA_PATH_DEFAULT "?;?.lua"
+#endif
+
+
+static const char *getpath (lua_State *L) {
+ const char *path;
+ lua_getglobal(L, LUA_PATH); /* try global variable */
+ path = lua_tostring(L, -1);
+ lua_pop(L, 1);
+ if (path) return path;
+ path = getenv(LUA_PATH); /* else try environment variable */
+ if (path) return path;
+ return LUA_PATH_DEFAULT; /* else use default */
+}
+
+
+static const char *pushnextpath (lua_State *L, const char *path) {
+ const char *l;
+ if (*path == '\0') return NULL; /* no more paths */
+ if (*path == LUA_PATH_SEP) path++; /* skip separator */
+ l = strchr(path, LUA_PATH_SEP); /* find next separator */
+ if (l == NULL) l = path+strlen(path);
+ lua_pushlstring(L, path, l - path); /* directory name */
+ return l;
+}
+
+
+static void pushcomposename (lua_State *L) {
+ const char *path = lua_tostring(L, -1);
+ const char *wild;
+ int n = 1;
+ while ((wild = strchr(path, LUA_PATH_MARK)) != NULL) {
+ /* is there stack space for prefix, name, and eventual last sufix? */
+ luaL_checkstack(L, 3, "too many marks in a path component");
+ lua_pushlstring(L, path, wild - path); /* push prefix */
+ lua_pushvalue(L, 1); /* push package name (in place of MARK) */
+ path = wild + 1; /* continue after MARK */
+ n += 2;
+ }
+ lua_pushstring(L, path); /* push last sufix (`n' already includes this) */
+ lua_concat(L, n);
+}
+
+
+static int luaB_require (lua_State *L) {
+ const char *path;
+ int status = LUA_ERRFILE; /* not found (yet) */
+ luaL_checkstring(L, 1);
+ lua_settop(L, 1);
+ lua_getglobal(L, REQTAB);
+ if (!lua_istable(L, 2)) return luaL_error(L, "`" REQTAB "' is not a table");
+ path = getpath(L);
+ lua_pushvalue(L, 1); /* check package's name in book-keeping table */
+ lua_rawget(L, 2);
+ if (lua_toboolean(L, -1)) /* is it there? */
+ return 1; /* package is already loaded; return its result */
+ else { /* must load it */
+ while (status == LUA_ERRFILE) {
+ lua_settop(L, 3); /* reset stack position */
+ if ((path = pushnextpath(L, path)) == NULL) break;
+ pushcomposename(L);
+ status = luaL_loadfile(L, lua_tostring(L, -1)); /* try to load it */
+ }
+ }
+ switch (status) {
+ case 0: {
+ lua_getglobal(L, "_REQUIREDNAME"); /* save previous name */
+ lua_insert(L, -2); /* put it below function */
+ lua_pushvalue(L, 1);
+ lua_setglobal(L, "_REQUIREDNAME"); /* set new name */
+ lua_call(L, 0, 1); /* run loaded module */
+ lua_insert(L, -2); /* put result below previous name */
+ lua_setglobal(L, "_REQUIREDNAME"); /* reset to previous name */
+ if (lua_isnil(L, -1)) { /* no/nil return? */
+ lua_pushboolean(L, 1);
+ lua_replace(L, -2); /* replace to true */
+ }
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, 2); /* mark it as loaded */
+ return 1; /* return value */
+ }
+ case LUA_ERRFILE: { /* file not found */
+ return luaL_error(L, "could not load package `%s' from path `%s'",
+ lua_tostring(L, 1), getpath(L));
+ }
+ default: {
+ return luaL_error(L, "error loading package `%s' (%s)",
+ lua_tostring(L, 1), lua_tostring(L, -1));
+ }
+ }
+}
+
+/* }====================================================== */
+
+
+static const luaL_reg base_funcs[] = {
+ {"error", luaB_error},
+ {"getmetatable", luaB_getmetatable},
+ {"setmetatable", luaB_setmetatable},
+ {"getfenv", luaB_getfenv},
+ {"setfenv", luaB_setfenv},
+ {"next", luaB_next},
+ {"ipairs", luaB_ipairs},
+ {"pairs", luaB_pairs},
+ {"print", luaB_print},
+ {"tonumber", luaB_tonumber},
+ {"tostring", luaB_tostring},
+ {"type", luaB_type},
+ {"assert", luaB_assert},
+ {"unpack", luaB_unpack},
+ {"rawequal", luaB_rawequal},
+ {"rawget", luaB_rawget},
+ {"rawset", luaB_rawset},
+ {"pcall", luaB_pcall},
+ {"xpcall", luaB_xpcall},
+ {"collectgarbage", luaB_collectgarbage},
+ {"gcinfo", luaB_gcinfo},
+ {"loadfile", luaB_loadfile},
+ {"dofile", luaB_dofile},
+ {"loadstring", luaB_loadstring},
+ {"require", luaB_require},
+ {NULL, NULL}
+};
+
+
+/*
+** {======================================================
+** Coroutine library
+** =======================================================
+*/
+
+static int auxresume (lua_State *L, lua_State *co, int narg) {
+ int status;
+ if (!lua_checkstack(co, narg))
+ luaL_error(L, "too many arguments to resume");
+ lua_xmove(L, co, narg);
+ status = lua_resume(co, narg);
+ if (status == 0) {
+ int nres = lua_gettop(co);
+ if (!lua_checkstack(L, nres))
+ luaL_error(L, "too many results to resume");
+ lua_xmove(co, L, nres); /* move yielded values */
+ return nres;
+ }
+ else {
+ lua_xmove(co, L, 1); /* move error message */
+ return -1; /* error flag */
+ }
+}
+
+
+static int luaB_coresume (lua_State *L) {
+ lua_State *co = lua_tothread(L, 1);
+ int r;
+ luaL_argcheck(L, co, 1, "coroutine expected");
+ r = auxresume(L, co, lua_gettop(L) - 1);
+ if (r < 0) {
+ lua_pushboolean(L, 0);
+ lua_insert(L, -2);
+ return 2; /* return false + error message */
+ }
+ else {
+ lua_pushboolean(L, 1);
+ lua_insert(L, -(r + 1));
+ return r + 1; /* return true + `resume' returns */
+ }
+}
+
+
+static int luaB_auxwrap (lua_State *L) {
+ lua_State *co = lua_tothread(L, lua_upvalueindex(1));
+ int r = auxresume(L, co, lua_gettop(L));
+ if (r < 0) {
+ if (lua_isstring(L, -1)) { /* error object is a string? */
+ luaL_where(L, 1); /* add extra info */
+ lua_insert(L, -2);
+ lua_concat(L, 2);
+ }
+ lua_error(L); /* propagate error */
+ }
+ return r;
+}
+
+
+static int luaB_cocreate (lua_State *L) {
+ lua_State *NL = lua_newthread(L);
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
+ "Lua function expected");
+ lua_pushvalue(L, 1); /* move function to top */
+ lua_xmove(L, NL, 1); /* move function from L to NL */
+ return 1;
+}
+
+
+static int luaB_cowrap (lua_State *L) {
+ luaB_cocreate(L);
+ lua_pushcclosure(L, luaB_auxwrap, 1);
+ return 1;
+}
+
+
+static int luaB_yield (lua_State *L) {
+ return lua_yield(L, lua_gettop(L));
+}
+
+
+static int luaB_costatus (lua_State *L) {
+ lua_State *co = lua_tothread(L, 1);
+ luaL_argcheck(L, co, 1, "coroutine expected");
+ if (L == co) lua_pushliteral(L, "running");
+ else {
+ lua_Debug ar;
+ if (lua_getstack(co, 0, &ar) == 0 && lua_gettop(co) == 0)
+ lua_pushliteral(L, "dead");
+ else
+ lua_pushliteral(L, "suspended");
+ }
+ return 1;
+}
+
+
+static const luaL_reg co_funcs[] = {
+ {"create", luaB_cocreate},
+ {"wrap", luaB_cowrap},
+ {"resume", luaB_coresume},
+ {"yield", luaB_yield},
+ {"status", luaB_costatus},
+ {NULL, NULL}
+};
+
+/* }====================================================== */
+
+
+
+static void base_open (lua_State *L) {
+ lua_pushliteral(L, "_G");
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ luaL_openlib(L, NULL, base_funcs, 0); /* open lib into global table */
+ lua_pushliteral(L, "_VERSION");
+ lua_pushliteral(L, LUA_VERSION);
+ lua_rawset(L, -3); /* set global _VERSION */
+ /* `newproxy' needs a weaktable as upvalue */
+ lua_pushliteral(L, "newproxy");
+ lua_newtable(L); /* new table `w' */
+ lua_pushvalue(L, -1); /* `w' will be its own metatable */
+ lua_setmetatable(L, -2);
+ lua_pushliteral(L, "__mode");
+ lua_pushliteral(L, "k");
+ lua_rawset(L, -3); /* metatable(w).__mode = "k" */
+ lua_pushcclosure(L, luaB_newproxy, 1);
+ lua_rawset(L, -3); /* set global `newproxy' */
+ lua_rawset(L, -1); /* set global _G */
+}
+
+
+LUALIB_API int luaopen_base (lua_State *L) {
+ base_open(L);
+ luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0);
+ lua_newtable(L);
+ lua_setglobal(L, REQTAB);
+ return 0;
+}
+
diff --git a/lib/lua/src/LuaLib/ldblib.c b/lib/lua/src/LuaLib/ldblib.c index fcc35e4..455b89f 100644 --- a/lib/lua/src/LuaLib/ldblib.c +++ b/lib/lua/src/LuaLib/ldblib.c @@ -1,299 +1,299 @@ -/* -** $Id: ldblib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Interface from Lua to its debug API -** See Copyright Notice in lua.h -*/ - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define ldblib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - - -static void settabss (lua_State *L, const char *i, const char *v) { - lua_pushstring(L, i); - lua_pushstring(L, v); - lua_rawset(L, -3); -} - - -static void settabsi (lua_State *L, const char *i, int v) { - lua_pushstring(L, i); - lua_pushnumber(L, (lua_Number)v); - lua_rawset(L, -3); -} - - -static int getinfo (lua_State *L) { - lua_Debug ar; - const char *options = luaL_optstring(L, 2, "flnSu"); - if (lua_isnumber(L, 1)) { - if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) { - lua_pushnil(L); /* level out of range */ - return 1; - } - } - else if (lua_isfunction(L, 1)) { - lua_pushfstring(L, ">%s", options); - options = lua_tostring(L, -1); - lua_pushvalue(L, 1); - } - else - return luaL_argerror(L, 1, "function or level expected"); - if (!lua_getinfo(L, options, &ar)) - return luaL_argerror(L, 2, "invalid option"); - lua_newtable(L); - for (; *options; options++) { - switch (*options) { - case 'S': - settabss(L, "source", ar.source); - settabss(L, "short_src", ar.short_src); - settabsi(L, "linedefined", ar.linedefined); - settabss(L, "what", ar.what); - break; - case 'l': - settabsi(L, "currentline", ar.currentline); - break; - case 'u': - settabsi(L, "nups", ar.nups); - break; - case 'n': - settabss(L, "name", ar.name); - settabss(L, "namewhat", ar.namewhat); - break; - case 'f': - lua_pushliteral(L, "func"); - lua_pushvalue(L, -3); - lua_rawset(L, -3); - break; - } - } - return 1; /* return table */ -} - - -static int getlocal (lua_State *L) { - lua_Debug ar; - const char *name; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - name = lua_getlocal(L, &ar, luaL_checkint(L, 2)); - if (name) { - lua_pushstring(L, name); - lua_pushvalue(L, -2); - return 2; - } - else { - lua_pushnil(L); - return 1; - } -} - - -static int setlocal (lua_State *L) { - lua_Debug ar; - if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ - return luaL_argerror(L, 1, "level out of range"); - luaL_checkany(L, 3); - lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2))); - return 1; -} - - -static int auxupvalue (lua_State *L, int get) { - const char *name; - int n = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TFUNCTION); - if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ - name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); - if (name == NULL) return 0; - lua_pushstring(L, name); - lua_insert(L, -(get+1)); - return get + 1; -} - - -static int getupvalue (lua_State *L) { - return auxupvalue(L, 1); -} - - -static int setupvalue (lua_State *L) { - luaL_checkany(L, 3); - return auxupvalue(L, 0); -} - - - -static const char KEY_HOOK = 'h'; - - -static void hookf (lua_State *L, lua_Debug *ar) { - static const char *const hooknames[] = - {"call", "return", "line", "count", "tail return"}; - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); - if (lua_isfunction(L, -1)) { - lua_pushstring(L, hooknames[(int)ar->event]); - if (ar->currentline >= 0) - lua_pushnumber(L, (lua_Number)ar->currentline); - else lua_pushnil(L); - lua_assert(lua_getinfo(L, "lS", ar)); - lua_call(L, 2, 0); - } - else - lua_pop(L, 1); /* pop result from gettable */ -} - - -static int makemask (const char *smask, int count) { - int mask = 0; - if (strchr(smask, 'c')) mask |= LUA_MASKCALL; - if (strchr(smask, 'r')) mask |= LUA_MASKRET; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - return mask; -} - - -static char *unmakemask (int mask, char *smask) { - int i = 0; - if (mask & LUA_MASKCALL) smask[i++] = 'c'; - if (mask & LUA_MASKRET) smask[i++] = 'r'; - if (mask & LUA_MASKLINE) smask[i++] = 'l'; - smask[i] = '\0'; - return smask; -} - - -static int sethook (lua_State *L) { - if (lua_isnoneornil(L, 1)) { - lua_settop(L, 1); - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ - } - else { - const char *smask = luaL_checkstring(L, 2); - int count = luaL_optint(L, 3, 0); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_sethook(L, hookf, makemask(smask, count), count); - } - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_pushvalue(L, 1); - lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ - return 0; -} - - -static int gethook (lua_State *L) { - char buff[5]; - int mask = lua_gethookmask(L); - lua_Hook hook = lua_gethook(L); - if (hook != NULL && hook != hookf) /* external hook? */ - lua_pushliteral(L, "external hook"); - else { - lua_pushlightuserdata(L, (void *)&KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ - } - lua_pushstring(L, unmakemask(mask, buff)); - lua_pushnumber(L, (lua_Number)lua_gethookcount(L)); - return 3; -} - - -static int debug (lua_State *L) { - for (;;) { - char buffer[250]; - fputs("lua_debug> ", stderr); - if (fgets(buffer, sizeof(buffer), stdin) == 0 || - strcmp(buffer, "cont\n") == 0) - return 0; - lua_dostring(L, buffer); - lua_settop(L, 0); /* remove eventual returns */ - } -} - - -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ - -static int errorfb (lua_State *L) { - int level = 1; /* skip level 0 (it's this function) */ - int firstpart = 1; /* still before eventual `...' */ - lua_Debug ar; - if (lua_gettop(L) == 0) - lua_pushliteral(L, ""); - else if (!lua_isstring(L, 1)) return 1; /* no string message */ - else lua_pushliteral(L, "\n"); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L, level++, &ar)) { - if (level > LEVELS1 && firstpart) { - /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L, level+LEVELS2, &ar)) - level--; /* keep going */ - else { - lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ - level++; - } - firstpart = 0; - continue; - } - lua_pushliteral(L, "\n\t"); - lua_getinfo(L, "Snl", &ar); - lua_pushfstring(L, "%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - switch (*ar.namewhat) { - case 'g': /* global */ - case 'l': /* local */ - case 'f': /* field */ - case 'm': /* method */ - lua_pushfstring(L, " in function `%s'", ar.name); - break; - default: { - if (*ar.what == 'm') /* main? */ - lua_pushfstring(L, " in main chunk"); - else if (*ar.what == 'C' || *ar.what == 't') - lua_pushliteral(L, " ?"); /* C function or tail call */ - else - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } - } - lua_concat(L, lua_gettop(L)); - } - lua_concat(L, lua_gettop(L)); - return 1; -} - - -static const luaL_reg dblib[] = { - {"getlocal", getlocal}, - {"getinfo", getinfo}, - {"gethook", gethook}, - {"getupvalue", getupvalue}, - {"sethook", sethook}, - {"setlocal", setlocal}, - {"setupvalue", setupvalue}, - {"debug", debug}, - {"traceback", errorfb}, - {NULL, NULL} -}; - - -LUALIB_API int luaopen_debug (lua_State *L) { - luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); - lua_pushliteral(L, "_TRACEBACK"); - lua_pushcfunction(L, errorfb); - lua_settable(L, LUA_GLOBALSINDEX); - return 1; -} - +/*
+** $Id: ldblib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Interface from Lua to its debug API
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ldblib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+static void settabss (lua_State *L, const char *i, const char *v) {
+ lua_pushstring(L, i);
+ lua_pushstring(L, v);
+ lua_rawset(L, -3);
+}
+
+
+static void settabsi (lua_State *L, const char *i, int v) {
+ lua_pushstring(L, i);
+ lua_pushnumber(L, (lua_Number)v);
+ lua_rawset(L, -3);
+}
+
+
+static int getinfo (lua_State *L) {
+ lua_Debug ar;
+ const char *options = luaL_optstring(L, 2, "flnSu");
+ if (lua_isnumber(L, 1)) {
+ if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) {
+ lua_pushnil(L); /* level out of range */
+ return 1;
+ }
+ }
+ else if (lua_isfunction(L, 1)) {
+ lua_pushfstring(L, ">%s", options);
+ options = lua_tostring(L, -1);
+ lua_pushvalue(L, 1);
+ }
+ else
+ return luaL_argerror(L, 1, "function or level expected");
+ if (!lua_getinfo(L, options, &ar))
+ return luaL_argerror(L, 2, "invalid option");
+ lua_newtable(L);
+ for (; *options; options++) {
+ switch (*options) {
+ case 'S':
+ settabss(L, "source", ar.source);
+ settabss(L, "short_src", ar.short_src);
+ settabsi(L, "linedefined", ar.linedefined);
+ settabss(L, "what", ar.what);
+ break;
+ case 'l':
+ settabsi(L, "currentline", ar.currentline);
+ break;
+ case 'u':
+ settabsi(L, "nups", ar.nups);
+ break;
+ case 'n':
+ settabss(L, "name", ar.name);
+ settabss(L, "namewhat", ar.namewhat);
+ break;
+ case 'f':
+ lua_pushliteral(L, "func");
+ lua_pushvalue(L, -3);
+ lua_rawset(L, -3);
+ break;
+ }
+ }
+ return 1; /* return table */
+}
+
+
+static int getlocal (lua_State *L) {
+ lua_Debug ar;
+ const char *name;
+ if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */
+ return luaL_argerror(L, 1, "level out of range");
+ name = lua_getlocal(L, &ar, luaL_checkint(L, 2));
+ if (name) {
+ lua_pushstring(L, name);
+ lua_pushvalue(L, -2);
+ return 2;
+ }
+ else {
+ lua_pushnil(L);
+ return 1;
+ }
+}
+
+
+static int setlocal (lua_State *L) {
+ lua_Debug ar;
+ if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */
+ return luaL_argerror(L, 1, "level out of range");
+ luaL_checkany(L, 3);
+ lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2)));
+ return 1;
+}
+
+
+static int auxupvalue (lua_State *L, int get) {
+ const char *name;
+ int n = luaL_checkint(L, 2);
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */
+ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
+ if (name == NULL) return 0;
+ lua_pushstring(L, name);
+ lua_insert(L, -(get+1));
+ return get + 1;
+}
+
+
+static int getupvalue (lua_State *L) {
+ return auxupvalue(L, 1);
+}
+
+
+static int setupvalue (lua_State *L) {
+ luaL_checkany(L, 3);
+ return auxupvalue(L, 0);
+}
+
+
+
+static const char KEY_HOOK = 'h';
+
+
+static void hookf (lua_State *L, lua_Debug *ar) {
+ static const char *const hooknames[] =
+ {"call", "return", "line", "count", "tail return"};
+ lua_pushlightuserdata(L, (void *)&KEY_HOOK);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ if (lua_isfunction(L, -1)) {
+ lua_pushstring(L, hooknames[(int)ar->event]);
+ if (ar->currentline >= 0)
+ lua_pushnumber(L, (lua_Number)ar->currentline);
+ else lua_pushnil(L);
+ lua_assert(lua_getinfo(L, "lS", ar));
+ lua_call(L, 2, 0);
+ }
+ else
+ lua_pop(L, 1); /* pop result from gettable */
+}
+
+
+static int makemask (const char *smask, int count) {
+ int mask = 0;
+ if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
+ if (strchr(smask, 'r')) mask |= LUA_MASKRET;
+ if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
+ if (count > 0) mask |= LUA_MASKCOUNT;
+ return mask;
+}
+
+
+static char *unmakemask (int mask, char *smask) {
+ int i = 0;
+ if (mask & LUA_MASKCALL) smask[i++] = 'c';
+ if (mask & LUA_MASKRET) smask[i++] = 'r';
+ if (mask & LUA_MASKLINE) smask[i++] = 'l';
+ smask[i] = '\0';
+ return smask;
+}
+
+
+static int sethook (lua_State *L) {
+ if (lua_isnoneornil(L, 1)) {
+ lua_settop(L, 1);
+ lua_sethook(L, NULL, 0, 0); /* turn off hooks */
+ }
+ else {
+ const char *smask = luaL_checkstring(L, 2);
+ int count = luaL_optint(L, 3, 0);
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ lua_sethook(L, hookf, makemask(smask, count), count);
+ }
+ lua_pushlightuserdata(L, (void *)&KEY_HOOK);
+ lua_pushvalue(L, 1);
+ lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */
+ return 0;
+}
+
+
+static int gethook (lua_State *L) {
+ char buff[5];
+ int mask = lua_gethookmask(L);
+ lua_Hook hook = lua_gethook(L);
+ if (hook != NULL && hook != hookf) /* external hook? */
+ lua_pushliteral(L, "external hook");
+ else {
+ lua_pushlightuserdata(L, (void *)&KEY_HOOK);
+ lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
+ }
+ lua_pushstring(L, unmakemask(mask, buff));
+ lua_pushnumber(L, (lua_Number)lua_gethookcount(L));
+ return 3;
+}
+
+
+static int debug (lua_State *L) {
+ for (;;) {
+ char buffer[250];
+ fputs("lua_debug> ", stderr);
+ if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
+ strcmp(buffer, "cont\n") == 0)
+ return 0;
+ lua_dostring(L, buffer);
+ lua_settop(L, 0); /* remove eventual returns */
+ }
+}
+
+
+#define LEVELS1 12 /* size of the first part of the stack */
+#define LEVELS2 10 /* size of the second part of the stack */
+
+static int errorfb (lua_State *L) {
+ int level = 1; /* skip level 0 (it's this function) */
+ int firstpart = 1; /* still before eventual `...' */
+ lua_Debug ar;
+ if (lua_gettop(L) == 0)
+ lua_pushliteral(L, "");
+ else if (!lua_isstring(L, 1)) return 1; /* no string message */
+ else lua_pushliteral(L, "\n");
+ lua_pushliteral(L, "stack traceback:");
+ while (lua_getstack(L, level++, &ar)) {
+ if (level > LEVELS1 && firstpart) {
+ /* no more than `LEVELS2' more levels? */
+ if (!lua_getstack(L, level+LEVELS2, &ar))
+ level--; /* keep going */
+ else {
+ lua_pushliteral(L, "\n\t..."); /* too many levels */
+ while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */
+ level++;
+ }
+ firstpart = 0;
+ continue;
+ }
+ lua_pushliteral(L, "\n\t");
+ lua_getinfo(L, "Snl", &ar);
+ lua_pushfstring(L, "%s:", ar.short_src);
+ if (ar.currentline > 0)
+ lua_pushfstring(L, "%d:", ar.currentline);
+ switch (*ar.namewhat) {
+ case 'g': /* global */
+ case 'l': /* local */
+ case 'f': /* field */
+ case 'm': /* method */
+ lua_pushfstring(L, " in function `%s'", ar.name);
+ break;
+ default: {
+ if (*ar.what == 'm') /* main? */
+ lua_pushfstring(L, " in main chunk");
+ else if (*ar.what == 'C' || *ar.what == 't')
+ lua_pushliteral(L, " ?"); /* C function or tail call */
+ else
+ lua_pushfstring(L, " in function <%s:%d>",
+ ar.short_src, ar.linedefined);
+ }
+ }
+ lua_concat(L, lua_gettop(L));
+ }
+ lua_concat(L, lua_gettop(L));
+ return 1;
+}
+
+
+static const luaL_reg dblib[] = {
+ {"getlocal", getlocal},
+ {"getinfo", getinfo},
+ {"gethook", gethook},
+ {"getupvalue", getupvalue},
+ {"sethook", sethook},
+ {"setlocal", setlocal},
+ {"setupvalue", setupvalue},
+ {"debug", debug},
+ {"traceback", errorfb},
+ {NULL, NULL}
+};
+
+
+LUALIB_API int luaopen_debug (lua_State *L) {
+ luaL_openlib(L, LUA_DBLIBNAME, dblib, 0);
+ lua_pushliteral(L, "_TRACEBACK");
+ lua_pushcfunction(L, errorfb);
+ lua_settable(L, LUA_GLOBALSINDEX);
+ return 1;
+}
+
diff --git a/lib/lua/src/LuaLib/ldirlib.c b/lib/lua/src/LuaLib/ldirlib.c index b6760da..4e221b4 100644 --- a/lib/lua/src/LuaLib/ldirlib.c +++ b/lib/lua/src/LuaLib/ldirlib.c @@ -1,19 +1,14 @@ -#include <stdlib.h> +#include <stdlib.h>
#include <dirent.h>
-#include <errno.h> -#ifdef _WIN32 -#include <sys/stat.h> -#else -#include <sys/stat.h> -#include <sys/type.h> -#endif - -#define ldirlib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" +#include <errno.h>
+#include <sys/stat.h>
+
+#define ldirlib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
/* forward declaration for the iterator function */
static int dir_iter (lua_State *L);
@@ -73,13 +68,13 @@ static int dir_gc (lua_State *L) { if (d) closedir(d);
return 0;
}
- -static const luaL_reg dirlib[] = { - {NULL, NULL} +
+static const luaL_reg dirlib[] = {
+ {NULL, NULL}
};
int luaopen_dir (lua_State *L) {
- luaL_openlib(L, LUA_DIRLIBNAME, dirlib, 0); + luaL_openlib(L, LUA_DIRLIBNAME, dirlib, 0);
luaL_newmetatable(L, "LuaBook.dir");
/* set its __gc field */
diff --git a/lib/lua/src/LuaLib/liolib.c b/lib/lua/src/LuaLib/liolib.c index 100b3b7..3eeb05f 100644 --- a/lib/lua/src/LuaLib/liolib.c +++ b/lib/lua/src/LuaLib/liolib.c @@ -1,750 +1,750 @@ -/* -** $Id: liolib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Standard I/O (and system) library -** See Copyright Notice in lua.h -*/ - - -#include <errno.h> -#include <locale.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#define liolib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - - -/* -** by default, gcc does not get `tmpname' -*/ -#ifndef USE_TMPNAME -#ifdef __GNUC__ -#define USE_TMPNAME 0 -#else -#define USE_TMPNAME 1 -#endif -#endif - - -/* -** by default, posix systems get `popen' -*/ -#ifndef USE_POPEN -#ifdef _POSIX_C_SOURCE -#if _POSIX_C_SOURCE >= 2 -#define USE_POPEN 1 -#endif -#endif -#endif - -#ifndef USE_POPEN -#define USE_POPEN 0 -#endif - - - - -/* -** {====================================================== -** FILE Operations -** ======================================================= -*/ - - -#if !USE_POPEN -#define pclose(f) (-1) -#endif - - -#define FILEHANDLE "FILE*" - -#define IO_INPUT "_input" -#define IO_OUTPUT "_output" - - -static int pushresult (lua_State *L, int i, const char *filename) { - if (i) { - lua_pushboolean(L, 1); - return 1; - } - else { - lua_pushnil(L); - if (filename) - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); - else - lua_pushfstring(L, "%s", strerror(errno)); - lua_pushnumber(L, errno); - return 3; - } -} - - -static FILE **topfile (lua_State *L, int findex) { - FILE **f = (FILE **)luaL_checkudata(L, findex, FILEHANDLE); - if (f == NULL) luaL_argerror(L, findex, "bad file"); - return f; -} - - -static int io_type (lua_State *L) { - FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE); - if (f == NULL) lua_pushnil(L); - else if (*f == NULL) - lua_pushliteral(L, "closed file"); - else - lua_pushliteral(L, "file"); - return 1; -} - - -static FILE *tofile (lua_State *L, int findex) { - FILE **f = topfile(L, findex); - if (*f == NULL) - luaL_error(L, "attempt to use a closed file"); - return *f; -} - - - -/* -** When creating file handles, always creates a `closed' file handle -** before opening the actual file; so, if there is a memory error, the -** file is not left opened. -*/ -static FILE **newfile (lua_State *L) { - FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *)); - *pf = NULL; /* file handle is currently `closed' */ - luaL_getmetatable(L, FILEHANDLE); - lua_setmetatable(L, -2); - return pf; -} - - -/* -** assumes that top of the stack is the `io' library, and next is -** the `io' metatable -*/ -static void registerfile (lua_State *L, FILE *f, const char *name, - const char *impname) { - lua_pushstring(L, name); - *newfile(L) = f; - if (impname) { - lua_pushstring(L, impname); - lua_pushvalue(L, -2); - lua_settable(L, -6); /* metatable[impname] = file */ - } - lua_settable(L, -3); /* io[name] = file */ -} - - -static int aux_close (lua_State *L) { - FILE *f = tofile(L, 1); - if (f == stdin || f == stdout || f == stderr) - return 0; /* file cannot be closed */ - else { - int ok = (pclose(f) != -1) || (fclose(f) == 0); - if (ok) - *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */ - return ok; - } -} - - -static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) { - lua_pushstring(L, IO_OUTPUT); - lua_rawget(L, lua_upvalueindex(1)); - } - return pushresult(L, aux_close(L), NULL); -} - - -static int io_gc (lua_State *L) { - FILE **f = topfile(L, 1); - if (*f != NULL) /* ignore closed files */ - aux_close(L); - return 0; -} - - -static int io_tostring (lua_State *L) { - char buff[32]; - FILE **f = topfile(L, 1); - if (*f == NULL) - strcpy(buff, "closed"); - else - sprintf(buff, "%p", lua_touserdata(L, 1)); - lua_pushfstring(L, "file (%s)", buff); - return 1; -} - - -static int io_open (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - FILE **pf = newfile(L); - *pf = fopen(filename, mode); - return (*pf == NULL) ? pushresult(L, 0, filename) : 1; -} - - -static int io_popen (lua_State *L) { -#if !USE_POPEN - luaL_error(L, "`popen' not supported"); - return 0; -#else - const char *filename = luaL_checkstring(L, 1); - const char *mode = luaL_optstring(L, 2, "r"); - FILE **pf = newfile(L); - *pf = popen(filename, mode); - return (*pf == NULL) ? pushresult(L, 0, filename) : 1; -#endif -} - - -static int io_tmpfile (lua_State *L) { - FILE **pf = newfile(L); - *pf = tmpfile(); - return (*pf == NULL) ? pushresult(L, 0, NULL) : 1; -} - - -static FILE *getiofile (lua_State *L, const char *name) { - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); - return tofile(L, -1); -} - - -static int g_iofile (lua_State *L, const char *name, const char *mode) { - if (!lua_isnoneornil(L, 1)) { - const char *filename = lua_tostring(L, 1); - lua_pushstring(L, name); - if (filename) { - FILE **pf = newfile(L); - *pf = fopen(filename, mode); - if (*pf == NULL) { - lua_pushfstring(L, "%s: %s", filename, strerror(errno)); - luaL_argerror(L, 1, lua_tostring(L, -1)); - } - } - else { - tofile(L, 1); /* check that it's a valid file handle */ - lua_pushvalue(L, 1); - } - lua_rawset(L, lua_upvalueindex(1)); - } - /* return current value */ - lua_pushstring(L, name); - lua_rawget(L, lua_upvalueindex(1)); - return 1; -} - - -static int io_input (lua_State *L) { - return g_iofile(L, IO_INPUT, "r"); -} - - -static int io_output (lua_State *L) { - return g_iofile(L, IO_OUTPUT, "w"); -} - - -static int io_readline (lua_State *L); - - -static void aux_lines (lua_State *L, int idx, int close) { - lua_pushliteral(L, FILEHANDLE); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_pushvalue(L, idx); - lua_pushboolean(L, close); /* close/not close file when finished */ - lua_pushcclosure(L, io_readline, 3); -} - - -static int f_lines (lua_State *L) { - tofile(L, 1); /* check that it's a valid file handle */ - aux_lines(L, 1, 0); - return 1; -} - - -static int io_lines (lua_State *L) { - if (lua_isnoneornil(L, 1)) { /* no arguments? */ - lua_pushstring(L, IO_INPUT); - lua_rawget(L, lua_upvalueindex(1)); /* will iterate over default input */ - return f_lines(L); - } - else { - const char *filename = luaL_checkstring(L, 1); - FILE **pf = newfile(L); - *pf = fopen(filename, "r"); - luaL_argcheck(L, *pf, 1, strerror(errno)); - aux_lines(L, lua_gettop(L), 1); - return 1; - } -} - - -/* -** {====================================================== -** READ -** ======================================================= -*/ - - -static int read_number (lua_State *L, FILE *f) { - lua_Number d; - if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { - lua_pushnumber(L, d); - return 1; - } - else return 0; /* read fails */ -} - - -static int test_eof (lua_State *L, FILE *f) { - int c = getc(f); - ungetc(c, f); - lua_pushlstring(L, NULL, 0); - return (c != EOF); -} - - -static int read_line (lua_State *L, FILE *f) { - luaL_Buffer b; - luaL_buffinit(L, &b); - for (;;) { - size_t l; - char *p = luaL_prepbuffer(&b); - if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ - luaL_pushresult(&b); /* close buffer */ - return (lua_strlen(L, -1) > 0); /* check whether read something */ - } - l = strlen(p); - if (p[l-1] != '\n') - luaL_addsize(&b, l); - else { - luaL_addsize(&b, l - 1); /* do not include `eol' */ - luaL_pushresult(&b); /* close buffer */ - return 1; /* read at least an `eol' */ - } - } -} - - -static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t rlen; /* how much to read */ - size_t nr; /* number of chars actually read */ - luaL_Buffer b; - luaL_buffinit(L, &b); - rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ - do { - char *p = luaL_prepbuffer(&b); - if (rlen > n) rlen = n; /* cannot read more than asked */ - nr = fread(p, sizeof(char), rlen, f); - luaL_addsize(&b, nr); - n -= nr; /* still have to read `n' chars */ - } while (n > 0 && nr == rlen); /* until end of count or eof */ - luaL_pushresult(&b); /* close buffer */ - return (n == 0 || lua_strlen(L, -1) > 0); -} - - -static int g_read (lua_State *L, FILE *f, int first) { - int nargs = lua_gettop(L) - 1; - int success; - int n; - if (nargs == 0) { /* no arguments? */ - success = read_line(L, f); - n = first+1; /* to return 1 result */ - } - else { /* ensure stack space for all results and for auxlib's buffer */ - luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); - success = 1; - for (n = first; nargs-- && success; n++) { - if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)lua_tonumber(L, n); - success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); - } - else { - const char *p = lua_tostring(L, n); - luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); - switch (p[1]) { - case 'n': /* number */ - success = read_number(L, f); - break; - case 'l': /* line */ - success = read_line(L, f); - break; - case 'a': /* file */ - read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */ - success = 1; /* always success */ - break; - case 'w': /* word */ - return luaL_error(L, "obsolete option `*w' to `read'"); - default: - return luaL_argerror(L, n, "invalid format"); - } - } - } - } - if (!success) { - lua_pop(L, 1); /* remove last result */ - lua_pushnil(L); /* push nil instead */ - } - return n - first; -} - - -static int io_read (lua_State *L) { - return g_read(L, getiofile(L, IO_INPUT), 1); -} - - -static int f_read (lua_State *L) { - return g_read(L, tofile(L, 1), 2); -} - - -static int io_readline (lua_State *L) { - FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2)); - if (f == NULL) /* file is already closed? */ - luaL_error(L, "file is already closed"); - if (read_line(L, f)) return 1; - else { /* EOF */ - if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ - lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(2)); - aux_close(L); /* close it */ - } - return 0; - } -} - -/* }====================================================== */ - - -static int g_write (lua_State *L, FILE *f, int arg) { - int nargs = lua_gettop(L) - 1; - int status = 1; - for (; nargs--; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - status = status && - fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; - } - else { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - status = status && (fwrite(s, sizeof(char), l, f) == l); - } - } - return pushresult(L, status, NULL); -} - - -static int io_write (lua_State *L) { - return g_write(L, getiofile(L, IO_OUTPUT), 1); -} - - -static int f_write (lua_State *L) { - return g_write(L, tofile(L, 1), 2); -} - - -static int f_seek (lua_State *L) { - static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; - static const char *const modenames[] = {"set", "cur", "end", NULL}; - FILE *f = tofile(L, 1); - int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames); - long offset = luaL_optlong(L, 3, 0); - luaL_argcheck(L, op != -1, 2, "invalid mode"); - op = fseek(f, offset, mode[op]); - if (op) - return pushresult(L, 0, NULL); /* error */ - else { - lua_pushnumber(L, ftell(f)); - return 1; - } -} - - -static int io_flush (lua_State *L) { - return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); -} - - -static int f_flush (lua_State *L) { - return pushresult(L, fflush(tofile(L, 1)) == 0, NULL); -} - - -static const luaL_reg iolib[] = { - {"input", io_input}, - {"output", io_output}, - {"lines", io_lines}, - {"close", io_close}, - {"flush", io_flush}, - {"open", io_open}, - {"popen", io_popen}, - {"read", io_read}, - {"tmpfile", io_tmpfile}, - {"type", io_type}, - {"write", io_write}, - {NULL, NULL} -}; - - -static const luaL_reg flib[] = { - {"flush", f_flush}, - {"read", f_read}, - {"lines", f_lines}, - {"seek", f_seek}, - {"write", f_write}, - {"close", io_close}, - {"__gc", io_gc}, - {"__tostring", io_tostring}, - {NULL, NULL} -}; - - -static void createmeta (lua_State *L) { - luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */ - /* file methods */ - lua_pushliteral(L, "__index"); - lua_pushvalue(L, -2); /* push metatable */ - lua_rawset(L, -3); /* metatable.__index = metatable */ - luaL_openlib(L, NULL, flib, 0); -} - -/* }====================================================== */ - - -/* -** {====================================================== -** Other O.S. Operations -** ======================================================= -*/ - -static int io_execute (lua_State *L) { - lua_pushnumber(L, system(luaL_checkstring(L, 1))); - return 1; -} - - -static int io_remove (lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - return pushresult(L, remove(filename) == 0, filename); -} - - -static int io_rename (lua_State *L) { - const char *fromname = luaL_checkstring(L, 1); - const char *toname = luaL_checkstring(L, 2); - return pushresult(L, rename(fromname, toname) == 0, fromname); -} - - -static int io_tmpname (lua_State *L) { -#if !USE_TMPNAME - luaL_error(L, "`tmpname' not supported"); - return 0; -#else - char buff[L_tmpnam]; - if (tmpnam(buff) != buff) - return luaL_error(L, "unable to generate a unique filename in `tmpname'"); - lua_pushstring(L, buff); - return 1; -#endif -} - - -static int io_getenv (lua_State *L) { - lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ - return 1; -} - - -static int io_clock (lua_State *L) { - lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); - return 1; -} - - -/* -** {====================================================== -** Time/Date operations -** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, -** wday=%w+1, yday=%j, isdst=? } -** ======================================================= -*/ - -static void setfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); - lua_pushnumber(L, value); - lua_rawset(L, -3); -} - -static void setboolfield (lua_State *L, const char *key, int value) { - lua_pushstring(L, key); - lua_pushboolean(L, value); - lua_rawset(L, -3); -} - -static int getboolfield (lua_State *L, const char *key) { - int res; - lua_pushstring(L, key); - lua_gettable(L, -2); - res = lua_toboolean(L, -1); - lua_pop(L, 1); - return res; -} - - -static int getfield (lua_State *L, const char *key, int d) { - int res; - lua_pushstring(L, key); - lua_gettable(L, -2); - if (lua_isnumber(L, -1)) - res = (int)(lua_tonumber(L, -1)); - else { - if (d == -2) - return luaL_error(L, "field `%s' missing in date table", key); - res = d; - } - lua_pop(L, 1); - return res; -} - - -static int io_date (lua_State *L) { - const char *s = luaL_optstring(L, 1, "%c"); - time_t t = (time_t)(luaL_optnumber(L, 2, -1)); - struct tm *stm; - if (t == (time_t)(-1)) /* no time given? */ - t = time(NULL); /* use current time */ - if (*s == '!') { /* UTC? */ - stm = gmtime(&t); - s++; /* skip `!' */ - } - else - stm = localtime(&t); - if (stm == NULL) /* invalid date? */ - lua_pushnil(L); - else if (strcmp(s, "*t") == 0) { - lua_newtable(L); - setfield(L, "sec", stm->tm_sec); - setfield(L, "min", stm->tm_min); - setfield(L, "hour", stm->tm_hour); - setfield(L, "day", stm->tm_mday); - setfield(L, "month", stm->tm_mon+1); - setfield(L, "year", stm->tm_year+1900); - setfield(L, "wday", stm->tm_wday+1); - setfield(L, "yday", stm->tm_yday+1); - setboolfield(L, "isdst", stm->tm_isdst); - } - else { - char b[256]; - if (strftime(b, sizeof(b), s, stm)) - lua_pushstring(L, b); - else - return luaL_error(L, "`date' format too long"); - } - return 1; -} - - -static int io_time (lua_State *L) { - if (lua_isnoneornil(L, 1)) /* called without args? */ - lua_pushnumber(L, time(NULL)); /* return current time */ - else { - time_t t; - struct tm ts; - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0); - ts.tm_min = getfield(L, "min", 0); - ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -2); - ts.tm_mon = getfield(L, "month", -2) - 1; - ts.tm_year = getfield(L, "year", -2) - 1900; - ts.tm_isdst = getboolfield(L, "isdst"); - t = mktime(&ts); - if (t == (time_t)(-1)) - lua_pushnil(L); - else - lua_pushnumber(L, t); - } - return 1; -} - - -static int io_difftime (lua_State *L) { - lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), - (time_t)(luaL_optnumber(L, 2, 0)))); - return 1; -} - -/* }====================================================== */ - - -static int io_setloc (lua_State *L) { - static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, - LC_NUMERIC, LC_TIME}; - static const char *const catnames[] = {"all", "collate", "ctype", "monetary", - "numeric", "time", NULL}; - const char *l = lua_tostring(L, 1); - int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames); - luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected"); - luaL_argcheck(L, op != -1, 2, "invalid option"); - lua_pushstring(L, setlocale(cat[op], l)); - return 1; -} - - -static int io_exit (lua_State *L) { - exit(luaL_optint(L, 1, EXIT_SUCCESS)); - return 0; /* to avoid warnings */ -} - -static const luaL_reg syslib[] = { - {"clock", io_clock}, - {"date", io_date}, - {"difftime", io_difftime}, - {"execute", io_execute}, - {"exit", io_exit}, - {"getenv", io_getenv}, - {"remove", io_remove}, - {"rename", io_rename}, - {"setlocale", io_setloc}, - {"time", io_time}, - {"tmpname", io_tmpname}, - {NULL, NULL} -}; - -/* }====================================================== */ - - - -LUALIB_API int luaopen_io (lua_State *L) { - luaL_openlib(L, LUA_OSLIBNAME, syslib, 0); - createmeta(L); - lua_pushvalue(L, -1); - luaL_openlib(L, LUA_IOLIBNAME, iolib, 1); - /* put predefined file handles into `io' table */ - registerfile(L, stdin, "stdin", IO_INPUT); - registerfile(L, stdout, "stdout", IO_OUTPUT); - registerfile(L, stderr, "stderr", NULL); - return 1; -} - +/*
+** $Id: liolib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Standard I/O (and system) library
+** See Copyright Notice in lua.h
+*/
+
+
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define liolib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+/*
+** by default, gcc does not get `tmpname'
+*/
+#ifndef USE_TMPNAME
+#ifdef __GNUC__
+#define USE_TMPNAME 0
+#else
+#define USE_TMPNAME 1
+#endif
+#endif
+
+
+/*
+** by default, posix systems get `popen'
+*/
+#ifndef USE_POPEN
+#ifdef _POSIX_C_SOURCE
+#if _POSIX_C_SOURCE >= 2
+#define USE_POPEN 1
+#endif
+#endif
+#endif
+
+#ifndef USE_POPEN
+#define USE_POPEN 0
+#endif
+
+
+
+
+/*
+** {======================================================
+** FILE Operations
+** =======================================================
+*/
+
+
+#if !USE_POPEN
+#define pclose(f) (-1)
+#endif
+
+
+#define FILEHANDLE "FILE*"
+
+#define IO_INPUT "_input"
+#define IO_OUTPUT "_output"
+
+
+static int pushresult (lua_State *L, int i, const char *filename) {
+ if (i) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ else {
+ lua_pushnil(L);
+ if (filename)
+ lua_pushfstring(L, "%s: %s", filename, strerror(errno));
+ else
+ lua_pushfstring(L, "%s", strerror(errno));
+ lua_pushnumber(L, errno);
+ return 3;
+ }
+}
+
+
+static FILE **topfile (lua_State *L, int findex) {
+ FILE **f = (FILE **)luaL_checkudata(L, findex, FILEHANDLE);
+ if (f == NULL) luaL_argerror(L, findex, "bad file");
+ return f;
+}
+
+
+static int io_type (lua_State *L) {
+ FILE **f = (FILE **)luaL_checkudata(L, 1, FILEHANDLE);
+ if (f == NULL) lua_pushnil(L);
+ else if (*f == NULL)
+ lua_pushliteral(L, "closed file");
+ else
+ lua_pushliteral(L, "file");
+ return 1;
+}
+
+
+static FILE *tofile (lua_State *L, int findex) {
+ FILE **f = topfile(L, findex);
+ if (*f == NULL)
+ luaL_error(L, "attempt to use a closed file");
+ return *f;
+}
+
+
+
+/*
+** When creating file handles, always creates a `closed' file handle
+** before opening the actual file; so, if there is a memory error, the
+** file is not left opened.
+*/
+static FILE **newfile (lua_State *L) {
+ FILE **pf = (FILE **)lua_newuserdata(L, sizeof(FILE *));
+ *pf = NULL; /* file handle is currently `closed' */
+ luaL_getmetatable(L, FILEHANDLE);
+ lua_setmetatable(L, -2);
+ return pf;
+}
+
+
+/*
+** assumes that top of the stack is the `io' library, and next is
+** the `io' metatable
+*/
+static void registerfile (lua_State *L, FILE *f, const char *name,
+ const char *impname) {
+ lua_pushstring(L, name);
+ *newfile(L) = f;
+ if (impname) {
+ lua_pushstring(L, impname);
+ lua_pushvalue(L, -2);
+ lua_settable(L, -6); /* metatable[impname] = file */
+ }
+ lua_settable(L, -3); /* io[name] = file */
+}
+
+
+static int aux_close (lua_State *L) {
+ FILE *f = tofile(L, 1);
+ if (f == stdin || f == stdout || f == stderr)
+ return 0; /* file cannot be closed */
+ else {
+ int ok = (pclose(f) != -1) || (fclose(f) == 0);
+ if (ok)
+ *(FILE **)lua_touserdata(L, 1) = NULL; /* mark file as closed */
+ return ok;
+ }
+}
+
+
+static int io_close (lua_State *L) {
+ if (lua_isnone(L, 1)) {
+ lua_pushstring(L, IO_OUTPUT);
+ lua_rawget(L, lua_upvalueindex(1));
+ }
+ return pushresult(L, aux_close(L), NULL);
+}
+
+
+static int io_gc (lua_State *L) {
+ FILE **f = topfile(L, 1);
+ if (*f != NULL) /* ignore closed files */
+ aux_close(L);
+ return 0;
+}
+
+
+static int io_tostring (lua_State *L) {
+ char buff[32];
+ FILE **f = topfile(L, 1);
+ if (*f == NULL)
+ strcpy(buff, "closed");
+ else
+ sprintf(buff, "%p", lua_touserdata(L, 1));
+ lua_pushfstring(L, "file (%s)", buff);
+ return 1;
+}
+
+
+static int io_open (lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ const char *mode = luaL_optstring(L, 2, "r");
+ FILE **pf = newfile(L);
+ *pf = fopen(filename, mode);
+ return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
+}
+
+
+static int io_popen (lua_State *L) {
+#if !USE_POPEN
+ luaL_error(L, "`popen' not supported");
+ return 0;
+#else
+ const char *filename = luaL_checkstring(L, 1);
+ const char *mode = luaL_optstring(L, 2, "r");
+ FILE **pf = newfile(L);
+ *pf = popen(filename, mode);
+ return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
+#endif
+}
+
+
+static int io_tmpfile (lua_State *L) {
+ FILE **pf = newfile(L);
+ *pf = tmpfile();
+ return (*pf == NULL) ? pushresult(L, 0, NULL) : 1;
+}
+
+
+static FILE *getiofile (lua_State *L, const char *name) {
+ lua_pushstring(L, name);
+ lua_rawget(L, lua_upvalueindex(1));
+ return tofile(L, -1);
+}
+
+
+static int g_iofile (lua_State *L, const char *name, const char *mode) {
+ if (!lua_isnoneornil(L, 1)) {
+ const char *filename = lua_tostring(L, 1);
+ lua_pushstring(L, name);
+ if (filename) {
+ FILE **pf = newfile(L);
+ *pf = fopen(filename, mode);
+ if (*pf == NULL) {
+ lua_pushfstring(L, "%s: %s", filename, strerror(errno));
+ luaL_argerror(L, 1, lua_tostring(L, -1));
+ }
+ }
+ else {
+ tofile(L, 1); /* check that it's a valid file handle */
+ lua_pushvalue(L, 1);
+ }
+ lua_rawset(L, lua_upvalueindex(1));
+ }
+ /* return current value */
+ lua_pushstring(L, name);
+ lua_rawget(L, lua_upvalueindex(1));
+ return 1;
+}
+
+
+static int io_input (lua_State *L) {
+ return g_iofile(L, IO_INPUT, "r");
+}
+
+
+static int io_output (lua_State *L) {
+ return g_iofile(L, IO_OUTPUT, "w");
+}
+
+
+static int io_readline (lua_State *L);
+
+
+static void aux_lines (lua_State *L, int idx, int close) {
+ lua_pushliteral(L, FILEHANDLE);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ lua_pushvalue(L, idx);
+ lua_pushboolean(L, close); /* close/not close file when finished */
+ lua_pushcclosure(L, io_readline, 3);
+}
+
+
+static int f_lines (lua_State *L) {
+ tofile(L, 1); /* check that it's a valid file handle */
+ aux_lines(L, 1, 0);
+ return 1;
+}
+
+
+static int io_lines (lua_State *L) {
+ if (lua_isnoneornil(L, 1)) { /* no arguments? */
+ lua_pushstring(L, IO_INPUT);
+ lua_rawget(L, lua_upvalueindex(1)); /* will iterate over default input */
+ return f_lines(L);
+ }
+ else {
+ const char *filename = luaL_checkstring(L, 1);
+ FILE **pf = newfile(L);
+ *pf = fopen(filename, "r");
+ luaL_argcheck(L, *pf, 1, strerror(errno));
+ aux_lines(L, lua_gettop(L), 1);
+ return 1;
+ }
+}
+
+
+/*
+** {======================================================
+** READ
+** =======================================================
+*/
+
+
+static int read_number (lua_State *L, FILE *f) {
+ lua_Number d;
+ if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
+ lua_pushnumber(L, d);
+ return 1;
+ }
+ else return 0; /* read fails */
+}
+
+
+static int test_eof (lua_State *L, FILE *f) {
+ int c = getc(f);
+ ungetc(c, f);
+ lua_pushlstring(L, NULL, 0);
+ return (c != EOF);
+}
+
+
+static int read_line (lua_State *L, FILE *f) {
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (;;) {
+ size_t l;
+ char *p = luaL_prepbuffer(&b);
+ if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
+ luaL_pushresult(&b); /* close buffer */
+ return (lua_strlen(L, -1) > 0); /* check whether read something */
+ }
+ l = strlen(p);
+ if (p[l-1] != '\n')
+ luaL_addsize(&b, l);
+ else {
+ luaL_addsize(&b, l - 1); /* do not include `eol' */
+ luaL_pushresult(&b); /* close buffer */
+ return 1; /* read at least an `eol' */
+ }
+ }
+}
+
+
+static int read_chars (lua_State *L, FILE *f, size_t n) {
+ size_t rlen; /* how much to read */
+ size_t nr; /* number of chars actually read */
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ rlen = LUAL_BUFFERSIZE; /* try to read that much each time */
+ do {
+ char *p = luaL_prepbuffer(&b);
+ if (rlen > n) rlen = n; /* cannot read more than asked */
+ nr = fread(p, sizeof(char), rlen, f);
+ luaL_addsize(&b, nr);
+ n -= nr; /* still have to read `n' chars */
+ } while (n > 0 && nr == rlen); /* until end of count or eof */
+ luaL_pushresult(&b); /* close buffer */
+ return (n == 0 || lua_strlen(L, -1) > 0);
+}
+
+
+static int g_read (lua_State *L, FILE *f, int first) {
+ int nargs = lua_gettop(L) - 1;
+ int success;
+ int n;
+ if (nargs == 0) { /* no arguments? */
+ success = read_line(L, f);
+ n = first+1; /* to return 1 result */
+ }
+ else { /* ensure stack space for all results and for auxlib's buffer */
+ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
+ success = 1;
+ for (n = first; nargs-- && success; n++) {
+ if (lua_type(L, n) == LUA_TNUMBER) {
+ size_t l = (size_t)lua_tonumber(L, n);
+ success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
+ }
+ else {
+ const char *p = lua_tostring(L, n);
+ luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
+ switch (p[1]) {
+ case 'n': /* number */
+ success = read_number(L, f);
+ break;
+ case 'l': /* line */
+ success = read_line(L, f);
+ break;
+ case 'a': /* file */
+ read_chars(L, f, ~((size_t)0)); /* read MAX_SIZE_T chars */
+ success = 1; /* always success */
+ break;
+ case 'w': /* word */
+ return luaL_error(L, "obsolete option `*w' to `read'");
+ default:
+ return luaL_argerror(L, n, "invalid format");
+ }
+ }
+ }
+ }
+ if (!success) {
+ lua_pop(L, 1); /* remove last result */
+ lua_pushnil(L); /* push nil instead */
+ }
+ return n - first;
+}
+
+
+static int io_read (lua_State *L) {
+ return g_read(L, getiofile(L, IO_INPUT), 1);
+}
+
+
+static int f_read (lua_State *L) {
+ return g_read(L, tofile(L, 1), 2);
+}
+
+
+static int io_readline (lua_State *L) {
+ FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(2));
+ if (f == NULL) /* file is already closed? */
+ luaL_error(L, "file is already closed");
+ if (read_line(L, f)) return 1;
+ else { /* EOF */
+ if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
+ lua_settop(L, 0);
+ lua_pushvalue(L, lua_upvalueindex(2));
+ aux_close(L); /* close it */
+ }
+ return 0;
+ }
+}
+
+/* }====================================================== */
+
+
+static int g_write (lua_State *L, FILE *f, int arg) {
+ int nargs = lua_gettop(L) - 1;
+ int status = 1;
+ for (; nargs--; arg++) {
+ if (lua_type(L, arg) == LUA_TNUMBER) {
+ /* optimization: could be done exactly as for strings */
+ status = status &&
+ fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
+ }
+ else {
+ size_t l;
+ const char *s = luaL_checklstring(L, arg, &l);
+ status = status && (fwrite(s, sizeof(char), l, f) == l);
+ }
+ }
+ return pushresult(L, status, NULL);
+}
+
+
+static int io_write (lua_State *L) {
+ return g_write(L, getiofile(L, IO_OUTPUT), 1);
+}
+
+
+static int f_write (lua_State *L) {
+ return g_write(L, tofile(L, 1), 2);
+}
+
+
+static int f_seek (lua_State *L) {
+ static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
+ static const char *const modenames[] = {"set", "cur", "end", NULL};
+ FILE *f = tofile(L, 1);
+ int op = luaL_findstring(luaL_optstring(L, 2, "cur"), modenames);
+ long offset = luaL_optlong(L, 3, 0);
+ luaL_argcheck(L, op != -1, 2, "invalid mode");
+ op = fseek(f, offset, mode[op]);
+ if (op)
+ return pushresult(L, 0, NULL); /* error */
+ else {
+ lua_pushnumber(L, ftell(f));
+ return 1;
+ }
+}
+
+
+static int io_flush (lua_State *L) {
+ return pushresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
+}
+
+
+static int f_flush (lua_State *L) {
+ return pushresult(L, fflush(tofile(L, 1)) == 0, NULL);
+}
+
+
+static const luaL_reg iolib[] = {
+ {"input", io_input},
+ {"output", io_output},
+ {"lines", io_lines},
+ {"close", io_close},
+ {"flush", io_flush},
+ {"open", io_open},
+ {"popen", io_popen},
+ {"read", io_read},
+ {"tmpfile", io_tmpfile},
+ {"type", io_type},
+ {"write", io_write},
+ {NULL, NULL}
+};
+
+
+static const luaL_reg flib[] = {
+ {"flush", f_flush},
+ {"read", f_read},
+ {"lines", f_lines},
+ {"seek", f_seek},
+ {"write", f_write},
+ {"close", io_close},
+ {"__gc", io_gc},
+ {"__tostring", io_tostring},
+ {NULL, NULL}
+};
+
+
+static void createmeta (lua_State *L) {
+ luaL_newmetatable(L, FILEHANDLE); /* create new metatable for file handles */
+ /* file methods */
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, -2); /* push metatable */
+ lua_rawset(L, -3); /* metatable.__index = metatable */
+ luaL_openlib(L, NULL, flib, 0);
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** Other O.S. Operations
+** =======================================================
+*/
+
+static int io_execute (lua_State *L) {
+ lua_pushnumber(L, system(luaL_checkstring(L, 1)));
+ return 1;
+}
+
+
+static int io_remove (lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ return pushresult(L, remove(filename) == 0, filename);
+}
+
+
+static int io_rename (lua_State *L) {
+ const char *fromname = luaL_checkstring(L, 1);
+ const char *toname = luaL_checkstring(L, 2);
+ return pushresult(L, rename(fromname, toname) == 0, fromname);
+}
+
+
+static int io_tmpname (lua_State *L) {
+#if !USE_TMPNAME
+ luaL_error(L, "`tmpname' not supported");
+ return 0;
+#else
+ char buff[L_tmpnam];
+ if (tmpnam(buff) != buff)
+ return luaL_error(L, "unable to generate a unique filename in `tmpname'");
+ lua_pushstring(L, buff);
+ return 1;
+#endif
+}
+
+
+static int io_getenv (lua_State *L) {
+ lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */
+ return 1;
+}
+
+
+static int io_clock (lua_State *L) {
+ lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
+ return 1;
+}
+
+
+/*
+** {======================================================
+** Time/Date operations
+** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
+** wday=%w+1, yday=%j, isdst=? }
+** =======================================================
+*/
+
+static void setfield (lua_State *L, const char *key, int value) {
+ lua_pushstring(L, key);
+ lua_pushnumber(L, value);
+ lua_rawset(L, -3);
+}
+
+static void setboolfield (lua_State *L, const char *key, int value) {
+ lua_pushstring(L, key);
+ lua_pushboolean(L, value);
+ lua_rawset(L, -3);
+}
+
+static int getboolfield (lua_State *L, const char *key) {
+ int res;
+ lua_pushstring(L, key);
+ lua_gettable(L, -2);
+ res = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+ return res;
+}
+
+
+static int getfield (lua_State *L, const char *key, int d) {
+ int res;
+ lua_pushstring(L, key);
+ lua_gettable(L, -2);
+ if (lua_isnumber(L, -1))
+ res = (int)(lua_tonumber(L, -1));
+ else {
+ if (d == -2)
+ return luaL_error(L, "field `%s' missing in date table", key);
+ res = d;
+ }
+ lua_pop(L, 1);
+ return res;
+}
+
+
+static int io_date (lua_State *L) {
+ const char *s = luaL_optstring(L, 1, "%c");
+ time_t t = (time_t)(luaL_optnumber(L, 2, -1));
+ struct tm *stm;
+ if (t == (time_t)(-1)) /* no time given? */
+ t = time(NULL); /* use current time */
+ if (*s == '!') { /* UTC? */
+ stm = gmtime(&t);
+ s++; /* skip `!' */
+ }
+ else
+ stm = localtime(&t);
+ if (stm == NULL) /* invalid date? */
+ lua_pushnil(L);
+ else if (strcmp(s, "*t") == 0) {
+ lua_newtable(L);
+ setfield(L, "sec", stm->tm_sec);
+ setfield(L, "min", stm->tm_min);
+ setfield(L, "hour", stm->tm_hour);
+ setfield(L, "day", stm->tm_mday);
+ setfield(L, "month", stm->tm_mon+1);
+ setfield(L, "year", stm->tm_year+1900);
+ setfield(L, "wday", stm->tm_wday+1);
+ setfield(L, "yday", stm->tm_yday+1);
+ setboolfield(L, "isdst", stm->tm_isdst);
+ }
+ else {
+ char b[256];
+ if (strftime(b, sizeof(b), s, stm))
+ lua_pushstring(L, b);
+ else
+ return luaL_error(L, "`date' format too long");
+ }
+ return 1;
+}
+
+
+static int io_time (lua_State *L) {
+ if (lua_isnoneornil(L, 1)) /* called without args? */
+ lua_pushnumber(L, time(NULL)); /* return current time */
+ else {
+ time_t t;
+ struct tm ts;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ lua_settop(L, 1); /* make sure table is at the top */
+ ts.tm_sec = getfield(L, "sec", 0);
+ ts.tm_min = getfield(L, "min", 0);
+ ts.tm_hour = getfield(L, "hour", 12);
+ ts.tm_mday = getfield(L, "day", -2);
+ ts.tm_mon = getfield(L, "month", -2) - 1;
+ ts.tm_year = getfield(L, "year", -2) - 1900;
+ ts.tm_isdst = getboolfield(L, "isdst");
+ t = mktime(&ts);
+ if (t == (time_t)(-1))
+ lua_pushnil(L);
+ else
+ lua_pushnumber(L, t);
+ }
+ return 1;
+}
+
+
+static int io_difftime (lua_State *L) {
+ lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
+ (time_t)(luaL_optnumber(L, 2, 0))));
+ return 1;
+}
+
+/* }====================================================== */
+
+
+static int io_setloc (lua_State *L) {
+ static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
+ LC_NUMERIC, LC_TIME};
+ static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
+ "numeric", "time", NULL};
+ const char *l = lua_tostring(L, 1);
+ int op = luaL_findstring(luaL_optstring(L, 2, "all"), catnames);
+ luaL_argcheck(L, l || lua_isnoneornil(L, 1), 1, "string expected");
+ luaL_argcheck(L, op != -1, 2, "invalid option");
+ lua_pushstring(L, setlocale(cat[op], l));
+ return 1;
+}
+
+
+static int io_exit (lua_State *L) {
+ exit(luaL_optint(L, 1, EXIT_SUCCESS));
+ return 0; /* to avoid warnings */
+}
+
+static const luaL_reg syslib[] = {
+ {"clock", io_clock},
+ {"date", io_date},
+ {"difftime", io_difftime},
+ {"execute", io_execute},
+ {"exit", io_exit},
+ {"getenv", io_getenv},
+ {"remove", io_remove},
+ {"rename", io_rename},
+ {"setlocale", io_setloc},
+ {"time", io_time},
+ {"tmpname", io_tmpname},
+ {NULL, NULL}
+};
+
+/* }====================================================== */
+
+
+
+LUALIB_API int luaopen_io (lua_State *L) {
+ luaL_openlib(L, LUA_OSLIBNAME, syslib, 0);
+ createmeta(L);
+ lua_pushvalue(L, -1);
+ luaL_openlib(L, LUA_IOLIBNAME, iolib, 1);
+ /* put predefined file handles into `io' table */
+ registerfile(L, stdin, "stdin", IO_INPUT);
+ registerfile(L, stdout, "stdout", IO_OUTPUT);
+ registerfile(L, stderr, "stderr", NULL);
+ return 1;
+}
+
diff --git a/lib/lua/src/LuaLib/lmathlib.c b/lib/lua/src/LuaLib/lmathlib.c index b0f4ac7..2352fca 100644 --- a/lib/lua/src/LuaLib/lmathlib.c +++ b/lib/lua/src/LuaLib/lmathlib.c @@ -1,246 +1,246 @@ -/* -** $Id: lmathlib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Standard mathematical library -** See Copyright Notice in lua.h -*/ - - -#include <stdlib.h> -#include <math.h> - -#define lmathlib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#undef PI -#define PI (3.14159265358979323846) -#define RADIANS_PER_DEGREE (PI/180.0) - - - -/* -** If you want Lua to operate in degrees (instead of radians), -** define USE_DEGREES -*/ -#ifdef USE_DEGREES -#define FROMRAD(a) ((a)/RADIANS_PER_DEGREE) -#define TORAD(a) ((a)*RADIANS_PER_DEGREE) -#else -#define FROMRAD(a) (a) -#define TORAD(a) (a) -#endif - - -static int math_abs (lua_State *L) { - lua_pushnumber(L, fabs(luaL_checknumber(L, 1))); - return 1; -} - -static int math_sin (lua_State *L) { - lua_pushnumber(L, sin(TORAD(luaL_checknumber(L, 1)))); - return 1; -} - -static int math_cos (lua_State *L) { - lua_pushnumber(L, cos(TORAD(luaL_checknumber(L, 1)))); - return 1; -} - -static int math_tan (lua_State *L) { - lua_pushnumber(L, tan(TORAD(luaL_checknumber(L, 1)))); - return 1; -} - -static int math_asin (lua_State *L) { - lua_pushnumber(L, FROMRAD(asin(luaL_checknumber(L, 1)))); - return 1; -} - -static int math_acos (lua_State *L) { - lua_pushnumber(L, FROMRAD(acos(luaL_checknumber(L, 1)))); - return 1; -} - -static int math_atan (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan(luaL_checknumber(L, 1)))); - return 1; -} - -static int math_atan2 (lua_State *L) { - lua_pushnumber(L, FROMRAD(atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)))); - return 1; -} - -static int math_ceil (lua_State *L) { - lua_pushnumber(L, ceil(luaL_checknumber(L, 1))); - return 1; -} - -static int math_floor (lua_State *L) { - lua_pushnumber(L, floor(luaL_checknumber(L, 1))); - return 1; -} - -static int math_mod (lua_State *L) { - lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); - return 1; -} - -static int math_sqrt (lua_State *L) { - lua_pushnumber(L, sqrt(luaL_checknumber(L, 1))); - return 1; -} - -static int math_pow (lua_State *L) { - lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); - return 1; -} - -static int math_log (lua_State *L) { - lua_pushnumber(L, log(luaL_checknumber(L, 1))); - return 1; -} - -static int math_log10 (lua_State *L) { - lua_pushnumber(L, log10(luaL_checknumber(L, 1))); - return 1; -} - -static int math_exp (lua_State *L) { - lua_pushnumber(L, exp(luaL_checknumber(L, 1))); - return 1; -} - -static int math_deg (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); - return 1; -} - -static int math_rad (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); - return 1; -} - -static int math_frexp (lua_State *L) { - int e; - lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e)); - lua_pushnumber(L, e); - return 2; -} - -static int math_ldexp (lua_State *L) { - lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); - return 1; -} - - - -static int math_min (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - lua_Number dmin = luaL_checknumber(L, 1); - int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d < dmin) - dmin = d; - } - lua_pushnumber(L, dmin); - return 1; -} - - -static int math_max (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - lua_Number dmax = luaL_checknumber(L, 1); - int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d > dmax) - dmax = d; - } - lua_pushnumber(L, dmax); - return 1; -} - - -static int math_random (lua_State *L) { - /* the `%' avoids the (rare) case of r==1, and is needed also because on - some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ - lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; - switch (lua_gettop(L)) { /* check number of arguments */ - case 0: { /* no arguments */ - lua_pushnumber(L, r); /* Number between 0 and 1 */ - break; - } - case 1: { /* only upper limit */ - int u = luaL_checkint(L, 1); - luaL_argcheck(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */ - break; - } - case 2: { /* lower and upper limits */ - int l = luaL_checkint(L, 1); - int u = luaL_checkint(L, 2); - luaL_argcheck(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */ - break; - } - default: return luaL_error(L, "wrong number of arguments"); - } - return 1; -} - - -static int math_randomseed (lua_State *L) { - srand(luaL_checkint(L, 1)); - return 0; -} - - -static const luaL_reg mathlib[] = { - {"abs", math_abs}, - {"sin", math_sin}, - {"cos", math_cos}, - {"tan", math_tan}, - {"asin", math_asin}, - {"acos", math_acos}, - {"atan", math_atan}, - {"atan2", math_atan2}, - {"ceil", math_ceil}, - {"floor", math_floor}, - {"mod", math_mod}, - {"frexp", math_frexp}, - {"ldexp", math_ldexp}, - {"sqrt", math_sqrt}, - {"min", math_min}, - {"max", math_max}, - {"log", math_log}, - {"log10", math_log10}, - {"exp", math_exp}, - {"deg", math_deg}, - {"pow", math_pow}, - {"rad", math_rad}, - {"random", math_random}, - {"randomseed", math_randomseed}, - {NULL, NULL} -}; - - -/* -** Open math library -*/ -LUALIB_API int luaopen_math (lua_State *L) { - luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0); - lua_pushliteral(L, "pi"); - lua_pushnumber(L, PI); - lua_settable(L, -3); - lua_pushliteral(L, "__pow"); - lua_pushcfunction(L, math_pow); - lua_settable(L, LUA_GLOBALSINDEX); - return 1; -} - +/*
+** $Id: lmathlib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Standard mathematical library
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+#include <math.h>
+
+#define lmathlib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#undef PI
+#define PI (3.14159265358979323846)
+#define RADIANS_PER_DEGREE (PI/180.0)
+
+
+
+/*
+** If you want Lua to operate in degrees (instead of radians),
+** define USE_DEGREES
+*/
+#ifdef USE_DEGREES
+#define FROMRAD(a) ((a)/RADIANS_PER_DEGREE)
+#define TORAD(a) ((a)*RADIANS_PER_DEGREE)
+#else
+#define FROMRAD(a) (a)
+#define TORAD(a) (a)
+#endif
+
+
+static int math_abs (lua_State *L) {
+ lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_sin (lua_State *L) {
+ lua_pushnumber(L, sin(TORAD(luaL_checknumber(L, 1))));
+ return 1;
+}
+
+static int math_cos (lua_State *L) {
+ lua_pushnumber(L, cos(TORAD(luaL_checknumber(L, 1))));
+ return 1;
+}
+
+static int math_tan (lua_State *L) {
+ lua_pushnumber(L, tan(TORAD(luaL_checknumber(L, 1))));
+ return 1;
+}
+
+static int math_asin (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(asin(luaL_checknumber(L, 1))));
+ return 1;
+}
+
+static int math_acos (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(acos(luaL_checknumber(L, 1))));
+ return 1;
+}
+
+static int math_atan (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(atan(luaL_checknumber(L, 1))));
+ return 1;
+}
+
+static int math_atan2 (lua_State *L) {
+ lua_pushnumber(L, FROMRAD(atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))));
+ return 1;
+}
+
+static int math_ceil (lua_State *L) {
+ lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_floor (lua_State *L) {
+ lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_mod (lua_State *L) {
+ lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+ return 1;
+}
+
+static int math_sqrt (lua_State *L) {
+ lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_pow (lua_State *L) {
+ lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+ return 1;
+}
+
+static int math_log (lua_State *L) {
+ lua_pushnumber(L, log(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_log10 (lua_State *L) {
+ lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_exp (lua_State *L) {
+ lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
+ return 1;
+}
+
+static int math_deg (lua_State *L) {
+ lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
+ return 1;
+}
+
+static int math_rad (lua_State *L) {
+ lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
+ return 1;
+}
+
+static int math_frexp (lua_State *L) {
+ int e;
+ lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
+ lua_pushnumber(L, e);
+ return 2;
+}
+
+static int math_ldexp (lua_State *L) {
+ lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
+ return 1;
+}
+
+
+
+static int math_min (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ lua_Number dmin = luaL_checknumber(L, 1);
+ int i;
+ for (i=2; i<=n; i++) {
+ lua_Number d = luaL_checknumber(L, i);
+ if (d < dmin)
+ dmin = d;
+ }
+ lua_pushnumber(L, dmin);
+ return 1;
+}
+
+
+static int math_max (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ lua_Number dmax = luaL_checknumber(L, 1);
+ int i;
+ for (i=2; i<=n; i++) {
+ lua_Number d = luaL_checknumber(L, i);
+ if (d > dmax)
+ dmax = d;
+ }
+ lua_pushnumber(L, dmax);
+ return 1;
+}
+
+
+static int math_random (lua_State *L) {
+ /* the `%' avoids the (rare) case of r==1, and is needed also because on
+ some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
+ lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
+ switch (lua_gettop(L)) { /* check number of arguments */
+ case 0: { /* no arguments */
+ lua_pushnumber(L, r); /* Number between 0 and 1 */
+ break;
+ }
+ case 1: { /* only upper limit */
+ int u = luaL_checkint(L, 1);
+ luaL_argcheck(L, 1<=u, 1, "interval is empty");
+ lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */
+ break;
+ }
+ case 2: { /* lower and upper limits */
+ int l = luaL_checkint(L, 1);
+ int u = luaL_checkint(L, 2);
+ luaL_argcheck(L, l<=u, 2, "interval is empty");
+ lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */
+ break;
+ }
+ default: return luaL_error(L, "wrong number of arguments");
+ }
+ return 1;
+}
+
+
+static int math_randomseed (lua_State *L) {
+ srand(luaL_checkint(L, 1));
+ return 0;
+}
+
+
+static const luaL_reg mathlib[] = {
+ {"abs", math_abs},
+ {"sin", math_sin},
+ {"cos", math_cos},
+ {"tan", math_tan},
+ {"asin", math_asin},
+ {"acos", math_acos},
+ {"atan", math_atan},
+ {"atan2", math_atan2},
+ {"ceil", math_ceil},
+ {"floor", math_floor},
+ {"mod", math_mod},
+ {"frexp", math_frexp},
+ {"ldexp", math_ldexp},
+ {"sqrt", math_sqrt},
+ {"min", math_min},
+ {"max", math_max},
+ {"log", math_log},
+ {"log10", math_log10},
+ {"exp", math_exp},
+ {"deg", math_deg},
+ {"pow", math_pow},
+ {"rad", math_rad},
+ {"random", math_random},
+ {"randomseed", math_randomseed},
+ {NULL, NULL}
+};
+
+
+/*
+** Open math library
+*/
+LUALIB_API int luaopen_math (lua_State *L) {
+ luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0);
+ lua_pushliteral(L, "pi");
+ lua_pushnumber(L, PI);
+ lua_settable(L, -3);
+ lua_pushliteral(L, "__pow");
+ lua_pushcfunction(L, math_pow);
+ lua_settable(L, LUA_GLOBALSINDEX);
+ return 1;
+}
+
diff --git a/lib/lua/src/LuaLib/loadlib.c b/lib/lua/src/LuaLib/loadlib.c index b13c690..dc83283 100644 --- a/lib/lua/src/LuaLib/loadlib.c +++ b/lib/lua/src/LuaLib/loadlib.c @@ -1,205 +1,205 @@ -/* -** $Id: loadlib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Dynamic library loader for Lua -** See Copyright Notice in lua.h -* -* This Lua library exports a single function, called loadlib, which is -* called from Lua as loadlib(lib,init), where lib is the full name of the -* library to be loaded (including the complete path) and init is the name -* of a function to be called after the library is loaded. Typically, this -* function will register other functions, thus making the complete library -* available to Lua. The init function is *not* automatically called by -* loadlib. Instead, loadlib returns the init function as a Lua function -* that the client can call when it thinks is appropriate. In the case of -* errors, loadlib returns nil and two strings describing the error. -* The first string is supplied by the operating system; it should be -* informative and useful for error messages. The second string is "open", -* "init", or "absent" to identify the error and is meant to be used for -* making decisions without having to look into the first string (whose -* format is system-dependent). -* -* This module contains an implementation of loadlib for Unix systems that -* have dlfcn, an implementation for Windows, and a stub for other systems. -* See the list at the end of this file for some links to available -* implementations of dlfcn and interfaces to other native dynamic loaders -* on top of which loadlib could be implemented. -* -*/ - -#include "lua.h" -#include "lauxlib.h" -#include "lualib.h" - - -#undef LOADLIB - - -#ifdef USE_DLOPEN -#define LOADLIB -/* -* This is an implementation of loadlib based on the dlfcn interface. -* The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, -* NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least -* as an emulation layer on top of native functions. -*/ - -#include <dlfcn.h> - -static int loadlib(lua_State *L) -{ - const char *path=luaL_checkstring(L,1); - const char *init=luaL_checkstring(L,2); - void *lib=dlopen(path,RTLD_NOW); - if (lib!=NULL) - { - lua_CFunction f=(lua_CFunction) dlsym(lib,init); - if (f!=NULL) - { - lua_pushlightuserdata(L,lib); - lua_pushcclosure(L,f,1); - return 1; - } - } - /* else return appropriate error messages */ - lua_pushnil(L); - lua_pushstring(L,dlerror()); - lua_pushstring(L,(lib!=NULL) ? "init" : "open"); - if (lib!=NULL) dlclose(lib); - return 3; -} - -#endif - - - -/* -** In Windows, default is to use dll; otherwise, default is not to use dll -*/ -#ifndef USE_DLL -#ifdef _WIN32 -#define USE_DLL 1 -#else -#define USE_DLL 0 -#endif -#endif - - -#if USE_DLL -#define LOADLIB -/* -* This is an implementation of loadlib for Windows using native functions. -*/ - -#include <windows.h> - -static void pusherror(lua_State *L) -{ - int error=GetLastError(); - char buffer[128]; - if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - 0, error, 0, buffer, sizeof(buffer), 0)) - lua_pushstring(L,buffer); - else - lua_pushfstring(L,"system error %d\n",error); -} - -static int loadlib(lua_State *L) -{ - const char *path=luaL_checkstring(L,1); - const char *init=luaL_checkstring(L,2); - HINSTANCE lib=LoadLibrary(path); - if (lib!=NULL) - { - lua_CFunction f=(lua_CFunction) GetProcAddress(lib,init); - if (f!=NULL) - { - lua_pushlightuserdata(L,lib); - lua_pushcclosure(L,f,1); - return 1; - } - } - lua_pushnil(L); - pusherror(L); - lua_pushstring(L,(lib!=NULL) ? "init" : "open"); - if (lib!=NULL) FreeLibrary(lib); - return 3; -} - -#endif - - - -#ifndef LOADLIB -/* Fallback for other systems */ - -/* -** Those systems support dlopen, so they should have defined USE_DLOPEN. -** The default (no)implementation gives them a special error message. -*/ -#ifdef linux -#define LOADLIB -#endif - -#ifdef sun -#define LOADLIB -#endif - -#ifdef sgi -#define LOADLIB -#endif - -#ifdef BSD -#define LOADLIB -#endif - -#ifdef _WIN32 -#define LOADLIB -#endif - -#ifdef LOADLIB -#undef LOADLIB -#define LOADLIB "`loadlib' not installed (check your Lua configuration)" -#else -#define LOADLIB "`loadlib' not supported" -#endif - -static int loadlib(lua_State *L) -{ - lua_pushnil(L); - lua_pushliteral(L,LOADLIB); - lua_pushliteral(L,"absent"); - return 3; -} -#endif - -LUALIB_API int luaopen_loadlib (lua_State *L) -{ - lua_register(L,"loadlib",loadlib); - return 0; -} - -/* -* Here are some links to available implementations of dlfcn and -* interfaces to other native dynamic loaders on top of which loadlib -* could be implemented. Please send contributions and corrections to us. -* -* AIX -* Starting with AIX 4.2, dlfcn is included in the base OS. -* There is also an emulation package available. -* http://www.faqs.org/faqs/aix-faq/part4/section-21.html -* -* HPUX -* HPUX 11 has dlfcn. For HPUX 10 use shl_*. -* http://www.geda.seul.org/mailinglist/geda-dev37/msg00094.html -* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html -* -* Macintosh, Windows -* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html -* -* Mac OS X/Darwin -* http://www.opendarwin.org/projects/dlcompat/ -* -* GLIB has wrapper code for BeOS, OS2, Unix and Windows -* http://cvs.gnome.org/lxr/source/glib/gmodule/ -* -*/ +/*
+** $Id: loadlib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Dynamic library loader for Lua
+** See Copyright Notice in lua.h
+*
+* This Lua library exports a single function, called loadlib, which is
+* called from Lua as loadlib(lib,init), where lib is the full name of the
+* library to be loaded (including the complete path) and init is the name
+* of a function to be called after the library is loaded. Typically, this
+* function will register other functions, thus making the complete library
+* available to Lua. The init function is *not* automatically called by
+* loadlib. Instead, loadlib returns the init function as a Lua function
+* that the client can call when it thinks is appropriate. In the case of
+* errors, loadlib returns nil and two strings describing the error.
+* The first string is supplied by the operating system; it should be
+* informative and useful for error messages. The second string is "open",
+* "init", or "absent" to identify the error and is meant to be used for
+* making decisions without having to look into the first string (whose
+* format is system-dependent).
+*
+* This module contains an implementation of loadlib for Unix systems that
+* have dlfcn, an implementation for Windows, and a stub for other systems.
+* See the list at the end of this file for some links to available
+* implementations of dlfcn and interfaces to other native dynamic loaders
+* on top of which loadlib could be implemented.
+*
+*/
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#undef LOADLIB
+
+
+#ifdef USE_DLOPEN
+#define LOADLIB
+/*
+* This is an implementation of loadlib based on the dlfcn interface.
+* The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+* NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
+* as an emulation layer on top of native functions.
+*/
+
+#include <dlfcn.h>
+
+static int loadlib(lua_State *L)
+{
+ const char *path=luaL_checkstring(L,1);
+ const char *init=luaL_checkstring(L,2);
+ void *lib=dlopen(path,RTLD_NOW);
+ if (lib!=NULL)
+ {
+ lua_CFunction f=(lua_CFunction) dlsym(lib,init);
+ if (f!=NULL)
+ {
+ lua_pushlightuserdata(L,lib);
+ lua_pushcclosure(L,f,1);
+ return 1;
+ }
+ }
+ /* else return appropriate error messages */
+ lua_pushnil(L);
+ lua_pushstring(L,dlerror());
+ lua_pushstring(L,(lib!=NULL) ? "init" : "open");
+ if (lib!=NULL) dlclose(lib);
+ return 3;
+}
+
+#endif
+
+
+
+/*
+** In Windows, default is to use dll; otherwise, default is not to use dll
+*/
+#ifndef USE_DLL
+#ifdef _WIN32
+#define USE_DLL 1
+#else
+#define USE_DLL 0
+#endif
+#endif
+
+
+#if USE_DLL
+#define LOADLIB
+/*
+* This is an implementation of loadlib for Windows using native functions.
+*/
+
+#include <windows.h>
+
+static void pusherror(lua_State *L)
+{
+ int error=GetLastError();
+ char buffer[128];
+ if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, error, 0, buffer, sizeof(buffer), 0))
+ lua_pushstring(L,buffer);
+ else
+ lua_pushfstring(L,"system error %d\n",error);
+}
+
+static int loadlib(lua_State *L)
+{
+ const char *path=luaL_checkstring(L,1);
+ const char *init=luaL_checkstring(L,2);
+ HINSTANCE lib=LoadLibrary(path);
+ if (lib!=NULL)
+ {
+ lua_CFunction f=(lua_CFunction) GetProcAddress(lib,init);
+ if (f!=NULL)
+ {
+ lua_pushlightuserdata(L,lib);
+ lua_pushcclosure(L,f,1);
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ pusherror(L);
+ lua_pushstring(L,(lib!=NULL) ? "init" : "open");
+ if (lib!=NULL) FreeLibrary(lib);
+ return 3;
+}
+
+#endif
+
+
+
+#ifndef LOADLIB
+/* Fallback for other systems */
+
+/*
+** Those systems support dlopen, so they should have defined USE_DLOPEN.
+** The default (no)implementation gives them a special error message.
+*/
+#ifdef linux
+#define LOADLIB
+#endif
+
+#ifdef sun
+#define LOADLIB
+#endif
+
+#ifdef sgi
+#define LOADLIB
+#endif
+
+#ifdef BSD
+#define LOADLIB
+#endif
+
+#ifdef _WIN32
+#define LOADLIB
+#endif
+
+#ifdef LOADLIB
+#undef LOADLIB
+#define LOADLIB "`loadlib' not installed (check your Lua configuration)"
+#else
+#define LOADLIB "`loadlib' not supported"
+#endif
+
+static int loadlib(lua_State *L)
+{
+ lua_pushnil(L);
+ lua_pushliteral(L,LOADLIB);
+ lua_pushliteral(L,"absent");
+ return 3;
+}
+#endif
+
+LUALIB_API int luaopen_loadlib (lua_State *L)
+{
+ lua_register(L,"loadlib",loadlib);
+ return 0;
+}
+
+/*
+* Here are some links to available implementations of dlfcn and
+* interfaces to other native dynamic loaders on top of which loadlib
+* could be implemented. Please send contributions and corrections to us.
+*
+* AIX
+* Starting with AIX 4.2, dlfcn is included in the base OS.
+* There is also an emulation package available.
+* http://www.faqs.org/faqs/aix-faq/part4/section-21.html
+*
+* HPUX
+* HPUX 11 has dlfcn. For HPUX 10 use shl_*.
+* http://www.geda.seul.org/mailinglist/geda-dev37/msg00094.html
+* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html
+*
+* Macintosh, Windows
+* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html
+*
+* Mac OS X/Darwin
+* http://www.opendarwin.org/projects/dlcompat/
+*
+* GLIB has wrapper code for BeOS, OS2, Unix and Windows
+* http://cvs.gnome.org/lxr/source/glib/gmodule/
+*
+*/
diff --git a/lib/lua/src/LuaLib/lstrlib.c b/lib/lua/src/LuaLib/lstrlib.c index 1bffbfb..9b5fe8a 100644 --- a/lib/lua/src/LuaLib/lstrlib.c +++ b/lib/lua/src/LuaLib/lstrlib.c @@ -1,770 +1,770 @@ -/* -** $Id: lstrlib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Standard library for string operations and pattern-matching -** See Copyright Notice in lua.h -*/ - - -#include <ctype.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define lstrlib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -/* macro to `unsign' a character */ -#ifndef uchar -#define uchar(c) ((unsigned char)(c)) -#endif - - -typedef long sint32; /* a signed version for size_t */ - - -static int str_len (lua_State *L) { - size_t l; - luaL_checklstring(L, 1, &l); - lua_pushnumber(L, (lua_Number)l); - return 1; -} - - -static sint32 posrelat (sint32 pos, size_t len) { - /* relative string position: negative means back from end */ - return (pos>=0) ? pos : (sint32)len+pos+1; -} - - -static int str_sub (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - sint32 start = posrelat(luaL_checklong(L, 2), l); - sint32 end = posrelat(luaL_optlong(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (sint32)l) end = (sint32)l; - if (start <= end) - lua_pushlstring(L, s+start-1, end-start+1); - else lua_pushliteral(L, ""); - return 1; -} - - -static int str_lower (lua_State *L) { - size_t l; - size_t i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); - for (i=0; i<l; i++) - luaL_putchar(&b, tolower(uchar(s[i]))); - luaL_pushresult(&b); - return 1; -} - - -static int str_upper (lua_State *L) { - size_t l; - size_t i; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - luaL_buffinit(L, &b); - for (i=0; i<l; i++) - luaL_putchar(&b, toupper(uchar(s[i]))); - luaL_pushresult(&b); - return 1; -} - -static int str_rep (lua_State *L) { - size_t l; - luaL_Buffer b; - const char *s = luaL_checklstring(L, 1, &l); - int n = luaL_checkint(L, 2); - luaL_buffinit(L, &b); - while (n-- > 0) - luaL_addlstring(&b, s, l); - luaL_pushresult(&b); - return 1; -} - - -static int str_byte (lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - sint32 pos = posrelat(luaL_optlong(L, 2, 1), l); - if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */ - return 0; /* no answer */ - lua_pushnumber(L, uchar(s[pos-1])); - return 1; -} - - -static int str_char (lua_State *L) { - int n = lua_gettop(L); /* number of arguments */ - int i; - luaL_Buffer b; - luaL_buffinit(L, &b); - for (i=1; i<=n; i++) { - int c = luaL_checkint(L, i); - luaL_argcheck(L, uchar(c) == c, i, "invalid value"); - luaL_putchar(&b, uchar(c)); - } - luaL_pushresult(&b); - return 1; -} - - -static int writer (lua_State *L, const void* b, size_t size, void* B) { - (void)L; - luaL_addlstring((luaL_Buffer*) B, (const char *)b, size); - return 1; -} - - -static int str_dump (lua_State *L) { - luaL_Buffer b; - luaL_checktype(L, 1, LUA_TFUNCTION); - luaL_buffinit(L,&b); - if (!lua_dump(L, writer, &b)) - luaL_error(L, "unable to dump given function"); - luaL_pushresult(&b); - return 1; -} - - - -/* -** {====================================================== -** PATTERN MATCHING -** ======================================================= -*/ - -#ifndef MAX_CAPTURES -#define MAX_CAPTURES 32 /* arbitrary limit */ -#endif - - -#define CAP_UNFINISHED (-1) -#define CAP_POSITION (-2) - -typedef struct MatchState { - const char *src_init; /* init of source string */ - const char *src_end; /* end (`\0') of source string */ - lua_State *L; - int level; /* total number of captures (finished or unfinished) */ - struct { - const char *init; - sint32 len; - } capture[MAX_CAPTURES]; -} MatchState; - - -#define ESC '%' -#define SPECIALS "^$*+?.([%-" - - -static int check_capture (MatchState *ms, int l) { - l -= '1'; - if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) - return luaL_error(ms->L, "invalid capture index"); - return l; -} - - -static int capture_to_close (MatchState *ms) { - int level = ms->level; - for (level--; level>=0; level--) - if (ms->capture[level].len == CAP_UNFINISHED) return level; - return luaL_error(ms->L, "invalid pattern capture"); -} - - -static const char *luaI_classend (MatchState *ms, const char *p) { - switch (*p++) { - case ESC: { - if (*p == '\0') - luaL_error(ms->L, "malformed pattern (ends with `%')"); - return p+1; - } - case '[': { - if (*p == '^') p++; - do { /* look for a `]' */ - if (*p == '\0') - luaL_error(ms->L, "malformed pattern (missing `]')"); - if (*(p++) == ESC && *p != '\0') - p++; /* skip escapes (e.g. `%]') */ - } while (*p != ']'); - return p+1; - } - default: { - return p; - } - } -} - - -static int match_class (int c, int cl) { - int res; - switch (tolower(cl)) { - case 'a' : res = isalpha(c); break; - case 'c' : res = iscntrl(c); break; - case 'd' : res = isdigit(c); break; - case 'l' : res = islower(c); break; - case 'p' : res = ispunct(c); break; - case 's' : res = isspace(c); break; - case 'u' : res = isupper(c); break; - case 'w' : res = isalnum(c); break; - case 'x' : res = isxdigit(c); break; - case 'z' : res = (c == 0); break; - default: return (cl == c); - } - return (islower(cl) ? res : !res); -} - - -static int matchbracketclass (int c, const char *p, const char *ec) { - int sig = 1; - if (*(p+1) == '^') { - sig = 0; - p++; /* skip the `^' */ - } - while (++p < ec) { - if (*p == ESC) { - p++; - if (match_class(c, *p)) - return sig; - } - else if ((*(p+1) == '-') && (p+2 < ec)) { - p+=2; - if (uchar(*(p-2)) <= c && c <= uchar(*p)) - return sig; - } - else if (uchar(*p) == c) return sig; - } - return !sig; -} - - -static int luaI_singlematch (int c, const char *p, const char *ep) { - switch (*p) { - case '.': return 1; /* matches any char */ - case ESC: return match_class(c, *(p+1)); - case '[': return matchbracketclass(c, p, ep-1); - default: return (uchar(*p) == c); - } -} - - -static const char *match (MatchState *ms, const char *s, const char *p); - - -static const char *matchbalance (MatchState *ms, const char *s, - const char *p) { - if (*p == 0 || *(p+1) == 0) - luaL_error(ms->L, "unbalanced pattern"); - if (*s != *p) return NULL; - else { - int b = *p; - int e = *(p+1); - int cont = 1; - while (++s < ms->src_end) { - if (*s == e) { - if (--cont == 0) return s+1; - } - else if (*s == b) cont++; - } - } - return NULL; /* string ends out of balance */ -} - - -static const char *max_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - sint32 i = 0; /* counts maximum expand for item */ - while ((s+i)<ms->src_end && luaI_singlematch(uchar(*(s+i)), p, ep)) - i++; - /* keeps trying to match with the maximum repetitions */ - while (i>=0) { - const char *res = match(ms, (s+i), ep+1); - if (res) return res; - i--; /* else didn't match; reduce 1 repetition to try again */ - } - return NULL; -} - - -static const char *min_expand (MatchState *ms, const char *s, - const char *p, const char *ep) { - for (;;) { - const char *res = match(ms, s, ep+1); - if (res != NULL) - return res; - else if (s<ms->src_end && luaI_singlematch(uchar(*s), p, ep)) - s++; /* try with one more repetition */ - else return NULL; - } -} - - -static const char *start_capture (MatchState *ms, const char *s, - const char *p, int what) { - const char *res; - int level = ms->level; - if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures"); - ms->capture[level].init = s; - ms->capture[level].len = what; - ms->level = level+1; - if ((res=match(ms, s, p)) == NULL) /* match failed? */ - ms->level--; /* undo capture */ - return res; -} - - -static const char *end_capture (MatchState *ms, const char *s, - const char *p) { - int l = capture_to_close(ms); - const char *res; - ms->capture[l].len = s - ms->capture[l].init; /* close capture */ - if ((res = match(ms, s, p)) == NULL) /* match failed? */ - ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ - return res; -} - - -static const char *match_capture (MatchState *ms, const char *s, int l) { - size_t len; - l = check_capture(ms, l); - len = ms->capture[l].len; - if ((size_t)(ms->src_end-s) >= len && - memcmp(ms->capture[l].init, s, len) == 0) - return s+len; - else return NULL; -} - - -static const char *match (MatchState *ms, const char *s, const char *p) { - init: /* using goto's to optimize tail recursion */ - switch (*p) { - case '(': { /* start capture */ - if (*(p+1) == ')') /* position capture? */ - return start_capture(ms, s, p+2, CAP_POSITION); - else - return start_capture(ms, s, p+1, CAP_UNFINISHED); - } - case ')': { /* end capture */ - return end_capture(ms, s, p+1); - } - case ESC: { - switch (*(p+1)) { - case 'b': { /* balanced string? */ - s = matchbalance(ms, s, p+2); - if (s == NULL) return NULL; - p+=4; goto init; /* else return match(ms, s, p+4); */ - } - case 'f': { /* frontier? */ - const char *ep; char previous; - p += 2; - if (*p != '[') - luaL_error(ms->L, "missing `[' after `%%f' in pattern"); - ep = luaI_classend(ms, p); /* points to what is next */ - previous = (s == ms->src_init) ? '\0' : *(s-1); - if (matchbracketclass(uchar(previous), p, ep-1) || - !matchbracketclass(uchar(*s), p, ep-1)) return NULL; - p=ep; goto init; /* else return match(ms, s, ep); */ - } - default: { - if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, *(p+1)); - if (s == NULL) return NULL; - p+=2; goto init; /* else return match(ms, s, p+2) */ - } - goto dflt; /* case default */ - } - } - } - case '\0': { /* end of pattern */ - return s; /* match succeeded */ - } - case '$': { - if (*(p+1) == '\0') /* is the `$' the last char in pattern? */ - return (s == ms->src_end) ? s : NULL; /* check end of string */ - else goto dflt; - } - default: dflt: { /* it is a pattern item */ - const char *ep = luaI_classend(ms, p); /* points to what is next */ - int m = s<ms->src_end && luaI_singlematch(uchar(*s), p, ep); - switch (*ep) { - case '?': { /* optional */ - const char *res; - if (m && ((res=match(ms, s+1, ep+1)) != NULL)) - return res; - p=ep+1; goto init; /* else return match(ms, s, ep+1); */ - } - case '*': { /* 0 or more repetitions */ - return max_expand(ms, s, p, ep); - } - case '+': { /* 1 or more repetitions */ - return (m ? max_expand(ms, s+1, p, ep) : NULL); - } - case '-': { /* 0 or more repetitions (minimum) */ - return min_expand(ms, s, p, ep); - } - default: { - if (!m) return NULL; - s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ - } - } - } - } -} - - - -static const char *lmemfind (const char *s1, size_t l1, - const char *s2, size_t l2) { - if (l2 == 0) return s1; /* empty strings are everywhere */ - else if (l2 > l1) return NULL; /* avoids a negative `l1' */ - else { - const char *init; /* to search for a `*s2' inside `s1' */ - l2--; /* 1st char will be checked by `memchr' */ - l1 = l1-l2; /* `s2' cannot be found after that */ - while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { - init++; /* 1st char is already checked */ - if (memcmp(init, s2+1, l2) == 0) - return init-1; - else { /* correct `l1' and `s1' to try again */ - l1 -= init-s1; - s1 = init; - } - } - return NULL; /* not found */ - } -} - - -static void push_onecapture (MatchState *ms, int i) { - int l = ms->capture[i].len; - if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); - if (l == CAP_POSITION) - lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1)); - else - lua_pushlstring(ms->L, ms->capture[i].init, l); -} - - -static int push_captures (MatchState *ms, const char *s, const char *e) { - int i; - luaL_checkstack(ms->L, ms->level, "too many captures"); - if (ms->level == 0 && s) { /* no explicit captures? */ - lua_pushlstring(ms->L, s, e-s); /* return whole match */ - return 1; - } - else { /* return all captures */ - for (i=0; i<ms->level; i++) - push_onecapture(ms, i); - return ms->level; /* number of strings pushed */ - } -} - - -static int str_find (lua_State *L) { - size_t l1, l2; - const char *s = luaL_checklstring(L, 1, &l1); - const char *p = luaL_checklstring(L, 2, &l2); - sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1; - if (init < 0) init = 0; - else if ((size_t)(init) > l1) init = (sint32)l1; - if (lua_toboolean(L, 4) || /* explicit request? */ - strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */ - /* do a plain search */ - const char *s2 = lmemfind(s+init, l1-init, p, l2); - if (s2) { - lua_pushnumber(L, (lua_Number)(s2-s+1)); - lua_pushnumber(L, (lua_Number)(s2-s+l2)); - return 2; - } - } - else { - MatchState ms; - int anchor = (*p == '^') ? (p++, 1) : 0; - const char *s1=s+init; - ms.L = L; - ms.src_init = s; - ms.src_end = s+l1; - do { - const char *res; - ms.level = 0; - if ((res=match(&ms, s1, p)) != NULL) { - lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */ - lua_pushnumber(L, (lua_Number)(res-s)); /* end */ - return push_captures(&ms, NULL, 0) + 2; - } - } while (s1++<ms.src_end && !anchor); - } - lua_pushnil(L); /* not found */ - return 1; -} - - -static int gfind_aux (lua_State *L) { - MatchState ms; - const char *s = lua_tostring(L, lua_upvalueindex(1)); - size_t ls = lua_strlen(L, lua_upvalueindex(1)); - const char *p = lua_tostring(L, lua_upvalueindex(2)); - const char *src; - ms.L = L; - ms.src_init = s; - ms.src_end = s+ls; - for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3)); - src <= ms.src_end; - src++) { - const char *e; - ms.level = 0; - if ((e = match(&ms, src, p)) != NULL) { - int newstart = e-s; - if (e == src) newstart++; /* empty match? go at least one position */ - lua_pushnumber(L, (lua_Number)newstart); - lua_replace(L, lua_upvalueindex(3)); - return push_captures(&ms, src, e); - } - } - return 0; /* not found */ -} - - -static int gfind (lua_State *L) { - luaL_checkstring(L, 1); - luaL_checkstring(L, 2); - lua_settop(L, 2); - lua_pushnumber(L, 0); - lua_pushcclosure(L, gfind_aux, 3); - return 1; -} - - -static void add_s (MatchState *ms, luaL_Buffer *b, - const char *s, const char *e) { - lua_State *L = ms->L; - if (lua_isstring(L, 3)) { - const char *news = lua_tostring(L, 3); - size_t l = lua_strlen(L, 3); - size_t i; - for (i=0; i<l; i++) { - if (news[i] != ESC) - luaL_putchar(b, news[i]); - else { - i++; /* skip ESC */ - if (!isdigit(uchar(news[i]))) - luaL_putchar(b, news[i]); - else { - int level = check_capture(ms, news[i]); - push_onecapture(ms, level); - luaL_addvalue(b); /* add capture to accumulated result */ - } - } - } - } - else { /* is a function */ - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - if (lua_isstring(L, -1)) - luaL_addvalue(b); /* add return to accumulated result */ - else - lua_pop(L, 1); /* function result is not a string: pop it */ - } -} - - -static int str_gsub (lua_State *L) { - size_t srcl; - const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checkstring(L, 2); - int max_s = luaL_optint(L, 4, srcl+1); - int anchor = (*p == '^') ? (p++, 1) : 0; - int n = 0; - MatchState ms; - luaL_Buffer b; - luaL_argcheck(L, - lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)), - 3, "string or function expected"); - luaL_buffinit(L, &b); - ms.L = L; - ms.src_init = src; - ms.src_end = src+srcl; - while (n < max_s) { - const char *e; - ms.level = 0; - e = match(&ms, src, p); - if (e) { - n++; - add_s(&ms, &b, src, e); - } - if (e && e>src) /* non empty match? */ - src = e; /* skip it */ - else if (src < ms.src_end) - luaL_putchar(&b, *src++); - else break; - if (anchor) break; - } - luaL_addlstring(&b, src, ms.src_end-src); - luaL_pushresult(&b); - lua_pushnumber(L, (lua_Number)n); /* number of substitutions */ - return 2; -} - -/* }====================================================== */ - - -/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ -#define MAX_ITEM 512 -/* maximum size of each format specification (such as '%-099.99d') */ -#define MAX_FORMAT 20 - - -static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - luaL_putchar(b, '"'); - while (l--) { - switch (*s) { - case '"': case '\\': case '\n': { - luaL_putchar(b, '\\'); - luaL_putchar(b, *s); - break; - } - case '\0': { - luaL_addlstring(b, "\\000", 4); - break; - } - default: { - luaL_putchar(b, *s); - break; - } - } - s++; - } - luaL_putchar(b, '"'); -} - - -static const char *scanformat (lua_State *L, const char *strfrmt, - char *form, int *hasprecision) { - const char *p = strfrmt; - while (strchr("-+ #0", *p)) p++; /* skip flags */ - if (isdigit(uchar(*p))) p++; /* skip width */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - if (*p == '.') { - p++; - *hasprecision = 1; - if (isdigit(uchar(*p))) p++; /* skip precision */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - } - if (isdigit(uchar(*p))) - luaL_error(L, "invalid format (width or precision too long)"); - if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */ - luaL_error(L, "invalid format (too long)"); - form[0] = '%'; - strncpy(form+1, strfrmt, p-strfrmt+1); - form[p-strfrmt+2] = 0; - return p; -} - - -static int str_format (lua_State *L) { - int arg = 1; - size_t sfl; - const char *strfrmt = luaL_checklstring(L, arg, &sfl); - const char *strfrmt_end = strfrmt+sfl; - luaL_Buffer b; - luaL_buffinit(L, &b); - while (strfrmt < strfrmt_end) { - if (*strfrmt != '%') - luaL_putchar(&b, *strfrmt++); - else if (*++strfrmt == '%') - luaL_putchar(&b, *strfrmt++); /* %% */ - else { /* format item */ - char form[MAX_FORMAT]; /* to store the format (`%...') */ - char buff[MAX_ITEM]; /* to store the formatted item */ - int hasprecision = 0; - if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$') - return luaL_error(L, "obsolete option (d$) to `format'"); - arg++; - strfrmt = scanformat(L, strfrmt, form, &hasprecision); - switch (*strfrmt++) { - case 'c': case 'd': case 'i': { - sprintf(buff, form, luaL_checkint(L, arg)); - break; - } - case 'o': case 'u': case 'x': case 'X': { - sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg))); - break; - } - case 'e': case 'E': case 'f': - case 'g': case 'G': { - sprintf(buff, form, luaL_checknumber(L, arg)); - break; - } - case 'q': { - luaI_addquoted(L, &b, arg); - continue; /* skip the `addsize' at the end */ - } - case 's': { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); - if (!hasprecision && l >= 100) { - /* no precision and string is too long to be formatted; - keep original string */ - lua_pushvalue(L, arg); - luaL_addvalue(&b); - continue; /* skip the `addsize' at the end */ - } - else { - sprintf(buff, form, s); - break; - } - } - default: { /* also treat cases `pnLlh' */ - return luaL_error(L, "invalid option to `format'"); - } - } - luaL_addlstring(&b, buff, strlen(buff)); - } - } - luaL_pushresult(&b); - return 1; -} - - -static const luaL_reg strlib[] = { - {"len", str_len}, - {"sub", str_sub}, - {"lower", str_lower}, - {"upper", str_upper}, - {"char", str_char}, - {"rep", str_rep}, - {"byte", str_byte}, - {"format", str_format}, - {"dump", str_dump}, - {"find", str_find}, - {"gfind", gfind}, - {"gsub", str_gsub}, - {NULL, NULL} -}; - - -/* -** Open string library -*/ -LUALIB_API int luaopen_string (lua_State *L) { - luaL_openlib(L, LUA_STRLIBNAME, strlib, 0); - return 1; -} - +/*
+** $Id: lstrlib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Standard library for string operations and pattern-matching
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define lstrlib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/* macro to `unsign' a character */
+#ifndef uchar
+#define uchar(c) ((unsigned char)(c))
+#endif
+
+
+typedef long sint32; /* a signed version for size_t */
+
+
+static int str_len (lua_State *L) {
+ size_t l;
+ luaL_checklstring(L, 1, &l);
+ lua_pushnumber(L, (lua_Number)l);
+ return 1;
+}
+
+
+static sint32 posrelat (sint32 pos, size_t len) {
+ /* relative string position: negative means back from end */
+ return (pos>=0) ? pos : (sint32)len+pos+1;
+}
+
+
+static int str_sub (lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ sint32 start = posrelat(luaL_checklong(L, 2), l);
+ sint32 end = posrelat(luaL_optlong(L, 3, -1), l);
+ if (start < 1) start = 1;
+ if (end > (sint32)l) end = (sint32)l;
+ if (start <= end)
+ lua_pushlstring(L, s+start-1, end-start+1);
+ else lua_pushliteral(L, "");
+ return 1;
+}
+
+
+static int str_lower (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_checklstring(L, 1, &l);
+ luaL_buffinit(L, &b);
+ for (i=0; i<l; i++)
+ luaL_putchar(&b, tolower(uchar(s[i])));
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static int str_upper (lua_State *L) {
+ size_t l;
+ size_t i;
+ luaL_Buffer b;
+ const char *s = luaL_checklstring(L, 1, &l);
+ luaL_buffinit(L, &b);
+ for (i=0; i<l; i++)
+ luaL_putchar(&b, toupper(uchar(s[i])));
+ luaL_pushresult(&b);
+ return 1;
+}
+
+static int str_rep (lua_State *L) {
+ size_t l;
+ luaL_Buffer b;
+ const char *s = luaL_checklstring(L, 1, &l);
+ int n = luaL_checkint(L, 2);
+ luaL_buffinit(L, &b);
+ while (n-- > 0)
+ luaL_addlstring(&b, s, l);
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static int str_byte (lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ sint32 pos = posrelat(luaL_optlong(L, 2, 1), l);
+ if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */
+ return 0; /* no answer */
+ lua_pushnumber(L, uchar(s[pos-1]));
+ return 1;
+}
+
+
+static int str_char (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ for (i=1; i<=n; i++) {
+ int c = luaL_checkint(L, i);
+ luaL_argcheck(L, uchar(c) == c, i, "invalid value");
+ luaL_putchar(&b, uchar(c));
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static int writer (lua_State *L, const void* b, size_t size, void* B) {
+ (void)L;
+ luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
+ return 1;
+}
+
+
+static int str_dump (lua_State *L) {
+ luaL_Buffer b;
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ luaL_buffinit(L,&b);
+ if (!lua_dump(L, writer, &b))
+ luaL_error(L, "unable to dump given function");
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+
+/*
+** {======================================================
+** PATTERN MATCHING
+** =======================================================
+*/
+
+#ifndef MAX_CAPTURES
+#define MAX_CAPTURES 32 /* arbitrary limit */
+#endif
+
+
+#define CAP_UNFINISHED (-1)
+#define CAP_POSITION (-2)
+
+typedef struct MatchState {
+ const char *src_init; /* init of source string */
+ const char *src_end; /* end (`\0') of source string */
+ lua_State *L;
+ int level; /* total number of captures (finished or unfinished) */
+ struct {
+ const char *init;
+ sint32 len;
+ } capture[MAX_CAPTURES];
+} MatchState;
+
+
+#define ESC '%'
+#define SPECIALS "^$*+?.([%-"
+
+
+static int check_capture (MatchState *ms, int l) {
+ l -= '1';
+ if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
+ return luaL_error(ms->L, "invalid capture index");
+ return l;
+}
+
+
+static int capture_to_close (MatchState *ms) {
+ int level = ms->level;
+ for (level--; level>=0; level--)
+ if (ms->capture[level].len == CAP_UNFINISHED) return level;
+ return luaL_error(ms->L, "invalid pattern capture");
+}
+
+
+static const char *luaI_classend (MatchState *ms, const char *p) {
+ switch (*p++) {
+ case ESC: {
+ if (*p == '\0')
+ luaL_error(ms->L, "malformed pattern (ends with `%')");
+ return p+1;
+ }
+ case '[': {
+ if (*p == '^') p++;
+ do { /* look for a `]' */
+ if (*p == '\0')
+ luaL_error(ms->L, "malformed pattern (missing `]')");
+ if (*(p++) == ESC && *p != '\0')
+ p++; /* skip escapes (e.g. `%]') */
+ } while (*p != ']');
+ return p+1;
+ }
+ default: {
+ return p;
+ }
+ }
+}
+
+
+static int match_class (int c, int cl) {
+ int res;
+ switch (tolower(cl)) {
+ case 'a' : res = isalpha(c); break;
+ case 'c' : res = iscntrl(c); break;
+ case 'd' : res = isdigit(c); break;
+ case 'l' : res = islower(c); break;
+ case 'p' : res = ispunct(c); break;
+ case 's' : res = isspace(c); break;
+ case 'u' : res = isupper(c); break;
+ case 'w' : res = isalnum(c); break;
+ case 'x' : res = isxdigit(c); break;
+ case 'z' : res = (c == 0); break;
+ default: return (cl == c);
+ }
+ return (islower(cl) ? res : !res);
+}
+
+
+static int matchbracketclass (int c, const char *p, const char *ec) {
+ int sig = 1;
+ if (*(p+1) == '^') {
+ sig = 0;
+ p++; /* skip the `^' */
+ }
+ while (++p < ec) {
+ if (*p == ESC) {
+ p++;
+ if (match_class(c, *p))
+ return sig;
+ }
+ else if ((*(p+1) == '-') && (p+2 < ec)) {
+ p+=2;
+ if (uchar(*(p-2)) <= c && c <= uchar(*p))
+ return sig;
+ }
+ else if (uchar(*p) == c) return sig;
+ }
+ return !sig;
+}
+
+
+static int luaI_singlematch (int c, const char *p, const char *ep) {
+ switch (*p) {
+ case '.': return 1; /* matches any char */
+ case ESC: return match_class(c, *(p+1));
+ case '[': return matchbracketclass(c, p, ep-1);
+ default: return (uchar(*p) == c);
+ }
+}
+
+
+static const char *match (MatchState *ms, const char *s, const char *p);
+
+
+static const char *matchbalance (MatchState *ms, const char *s,
+ const char *p) {
+ if (*p == 0 || *(p+1) == 0)
+ luaL_error(ms->L, "unbalanced pattern");
+ if (*s != *p) return NULL;
+ else {
+ int b = *p;
+ int e = *(p+1);
+ int cont = 1;
+ while (++s < ms->src_end) {
+ if (*s == e) {
+ if (--cont == 0) return s+1;
+ }
+ else if (*s == b) cont++;
+ }
+ }
+ return NULL; /* string ends out of balance */
+}
+
+
+static const char *max_expand (MatchState *ms, const char *s,
+ const char *p, const char *ep) {
+ sint32 i = 0; /* counts maximum expand for item */
+ while ((s+i)<ms->src_end && luaI_singlematch(uchar(*(s+i)), p, ep))
+ i++;
+ /* keeps trying to match with the maximum repetitions */
+ while (i>=0) {
+ const char *res = match(ms, (s+i), ep+1);
+ if (res) return res;
+ i--; /* else didn't match; reduce 1 repetition to try again */
+ }
+ return NULL;
+}
+
+
+static const char *min_expand (MatchState *ms, const char *s,
+ const char *p, const char *ep) {
+ for (;;) {
+ const char *res = match(ms, s, ep+1);
+ if (res != NULL)
+ return res;
+ else if (s<ms->src_end && luaI_singlematch(uchar(*s), p, ep))
+ s++; /* try with one more repetition */
+ else return NULL;
+ }
+}
+
+
+static const char *start_capture (MatchState *ms, const char *s,
+ const char *p, int what) {
+ const char *res;
+ int level = ms->level;
+ if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures");
+ ms->capture[level].init = s;
+ ms->capture[level].len = what;
+ ms->level = level+1;
+ if ((res=match(ms, s, p)) == NULL) /* match failed? */
+ ms->level--; /* undo capture */
+ return res;
+}
+
+
+static const char *end_capture (MatchState *ms, const char *s,
+ const char *p) {
+ int l = capture_to_close(ms);
+ const char *res;
+ ms->capture[l].len = s - ms->capture[l].init; /* close capture */
+ if ((res = match(ms, s, p)) == NULL) /* match failed? */
+ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
+ return res;
+}
+
+
+static const char *match_capture (MatchState *ms, const char *s, int l) {
+ size_t len;
+ l = check_capture(ms, l);
+ len = ms->capture[l].len;
+ if ((size_t)(ms->src_end-s) >= len &&
+ memcmp(ms->capture[l].init, s, len) == 0)
+ return s+len;
+ else return NULL;
+}
+
+
+static const char *match (MatchState *ms, const char *s, const char *p) {
+ init: /* using goto's to optimize tail recursion */
+ switch (*p) {
+ case '(': { /* start capture */
+ if (*(p+1) == ')') /* position capture? */
+ return start_capture(ms, s, p+2, CAP_POSITION);
+ else
+ return start_capture(ms, s, p+1, CAP_UNFINISHED);
+ }
+ case ')': { /* end capture */
+ return end_capture(ms, s, p+1);
+ }
+ case ESC: {
+ switch (*(p+1)) {
+ case 'b': { /* balanced string? */
+ s = matchbalance(ms, s, p+2);
+ if (s == NULL) return NULL;
+ p+=4; goto init; /* else return match(ms, s, p+4); */
+ }
+ case 'f': { /* frontier? */
+ const char *ep; char previous;
+ p += 2;
+ if (*p != '[')
+ luaL_error(ms->L, "missing `[' after `%%f' in pattern");
+ ep = luaI_classend(ms, p); /* points to what is next */
+ previous = (s == ms->src_init) ? '\0' : *(s-1);
+ if (matchbracketclass(uchar(previous), p, ep-1) ||
+ !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
+ p=ep; goto init; /* else return match(ms, s, ep); */
+ }
+ default: {
+ if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
+ s = match_capture(ms, s, *(p+1));
+ if (s == NULL) return NULL;
+ p+=2; goto init; /* else return match(ms, s, p+2) */
+ }
+ goto dflt; /* case default */
+ }
+ }
+ }
+ case '\0': { /* end of pattern */
+ return s; /* match succeeded */
+ }
+ case '$': {
+ if (*(p+1) == '\0') /* is the `$' the last char in pattern? */
+ return (s == ms->src_end) ? s : NULL; /* check end of string */
+ else goto dflt;
+ }
+ default: dflt: { /* it is a pattern item */
+ const char *ep = luaI_classend(ms, p); /* points to what is next */
+ int m = s<ms->src_end && luaI_singlematch(uchar(*s), p, ep);
+ switch (*ep) {
+ case '?': { /* optional */
+ const char *res;
+ if (m && ((res=match(ms, s+1, ep+1)) != NULL))
+ return res;
+ p=ep+1; goto init; /* else return match(ms, s, ep+1); */
+ }
+ case '*': { /* 0 or more repetitions */
+ return max_expand(ms, s, p, ep);
+ }
+ case '+': { /* 1 or more repetitions */
+ return (m ? max_expand(ms, s+1, p, ep) : NULL);
+ }
+ case '-': { /* 0 or more repetitions (minimum) */
+ return min_expand(ms, s, p, ep);
+ }
+ default: {
+ if (!m) return NULL;
+ s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
+ }
+ }
+ }
+ }
+}
+
+
+
+static const char *lmemfind (const char *s1, size_t l1,
+ const char *s2, size_t l2) {
+ if (l2 == 0) return s1; /* empty strings are everywhere */
+ else if (l2 > l1) return NULL; /* avoids a negative `l1' */
+ else {
+ const char *init; /* to search for a `*s2' inside `s1' */
+ l2--; /* 1st char will be checked by `memchr' */
+ l1 = l1-l2; /* `s2' cannot be found after that */
+ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
+ init++; /* 1st char is already checked */
+ if (memcmp(init, s2+1, l2) == 0)
+ return init-1;
+ else { /* correct `l1' and `s1' to try again */
+ l1 -= init-s1;
+ s1 = init;
+ }
+ }
+ return NULL; /* not found */
+ }
+}
+
+
+static void push_onecapture (MatchState *ms, int i) {
+ int l = ms->capture[i].len;
+ if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
+ if (l == CAP_POSITION)
+ lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1));
+ else
+ lua_pushlstring(ms->L, ms->capture[i].init, l);
+}
+
+
+static int push_captures (MatchState *ms, const char *s, const char *e) {
+ int i;
+ luaL_checkstack(ms->L, ms->level, "too many captures");
+ if (ms->level == 0 && s) { /* no explicit captures? */
+ lua_pushlstring(ms->L, s, e-s); /* return whole match */
+ return 1;
+ }
+ else { /* return all captures */
+ for (i=0; i<ms->level; i++)
+ push_onecapture(ms, i);
+ return ms->level; /* number of strings pushed */
+ }
+}
+
+
+static int str_find (lua_State *L) {
+ size_t l1, l2;
+ const char *s = luaL_checklstring(L, 1, &l1);
+ const char *p = luaL_checklstring(L, 2, &l2);
+ sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1;
+ if (init < 0) init = 0;
+ else if ((size_t)(init) > l1) init = (sint32)l1;
+ if (lua_toboolean(L, 4) || /* explicit request? */
+ strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */
+ /* do a plain search */
+ const char *s2 = lmemfind(s+init, l1-init, p, l2);
+ if (s2) {
+ lua_pushnumber(L, (lua_Number)(s2-s+1));
+ lua_pushnumber(L, (lua_Number)(s2-s+l2));
+ return 2;
+ }
+ }
+ else {
+ MatchState ms;
+ int anchor = (*p == '^') ? (p++, 1) : 0;
+ const char *s1=s+init;
+ ms.L = L;
+ ms.src_init = s;
+ ms.src_end = s+l1;
+ do {
+ const char *res;
+ ms.level = 0;
+ if ((res=match(&ms, s1, p)) != NULL) {
+ lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */
+ lua_pushnumber(L, (lua_Number)(res-s)); /* end */
+ return push_captures(&ms, NULL, 0) + 2;
+ }
+ } while (s1++<ms.src_end && !anchor);
+ }
+ lua_pushnil(L); /* not found */
+ return 1;
+}
+
+
+static int gfind_aux (lua_State *L) {
+ MatchState ms;
+ const char *s = lua_tostring(L, lua_upvalueindex(1));
+ size_t ls = lua_strlen(L, lua_upvalueindex(1));
+ const char *p = lua_tostring(L, lua_upvalueindex(2));
+ const char *src;
+ ms.L = L;
+ ms.src_init = s;
+ ms.src_end = s+ls;
+ for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3));
+ src <= ms.src_end;
+ src++) {
+ const char *e;
+ ms.level = 0;
+ if ((e = match(&ms, src, p)) != NULL) {
+ int newstart = e-s;
+ if (e == src) newstart++; /* empty match? go at least one position */
+ lua_pushnumber(L, (lua_Number)newstart);
+ lua_replace(L, lua_upvalueindex(3));
+ return push_captures(&ms, src, e);
+ }
+ }
+ return 0; /* not found */
+}
+
+
+static int gfind (lua_State *L) {
+ luaL_checkstring(L, 1);
+ luaL_checkstring(L, 2);
+ lua_settop(L, 2);
+ lua_pushnumber(L, 0);
+ lua_pushcclosure(L, gfind_aux, 3);
+ return 1;
+}
+
+
+static void add_s (MatchState *ms, luaL_Buffer *b,
+ const char *s, const char *e) {
+ lua_State *L = ms->L;
+ if (lua_isstring(L, 3)) {
+ const char *news = lua_tostring(L, 3);
+ size_t l = lua_strlen(L, 3);
+ size_t i;
+ for (i=0; i<l; i++) {
+ if (news[i] != ESC)
+ luaL_putchar(b, news[i]);
+ else {
+ i++; /* skip ESC */
+ if (!isdigit(uchar(news[i])))
+ luaL_putchar(b, news[i]);
+ else {
+ int level = check_capture(ms, news[i]);
+ push_onecapture(ms, level);
+ luaL_addvalue(b); /* add capture to accumulated result */
+ }
+ }
+ }
+ }
+ else { /* is a function */
+ int n;
+ lua_pushvalue(L, 3);
+ n = push_captures(ms, s, e);
+ lua_call(L, n, 1);
+ if (lua_isstring(L, -1))
+ luaL_addvalue(b); /* add return to accumulated result */
+ else
+ lua_pop(L, 1); /* function result is not a string: pop it */
+ }
+}
+
+
+static int str_gsub (lua_State *L) {
+ size_t srcl;
+ const char *src = luaL_checklstring(L, 1, &srcl);
+ const char *p = luaL_checkstring(L, 2);
+ int max_s = luaL_optint(L, 4, srcl+1);
+ int anchor = (*p == '^') ? (p++, 1) : 0;
+ int n = 0;
+ MatchState ms;
+ luaL_Buffer b;
+ luaL_argcheck(L,
+ lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
+ 3, "string or function expected");
+ luaL_buffinit(L, &b);
+ ms.L = L;
+ ms.src_init = src;
+ ms.src_end = src+srcl;
+ while (n < max_s) {
+ const char *e;
+ ms.level = 0;
+ e = match(&ms, src, p);
+ if (e) {
+ n++;
+ add_s(&ms, &b, src, e);
+ }
+ if (e && e>src) /* non empty match? */
+ src = e; /* skip it */
+ else if (src < ms.src_end)
+ luaL_putchar(&b, *src++);
+ else break;
+ if (anchor) break;
+ }
+ luaL_addlstring(&b, src, ms.src_end-src);
+ luaL_pushresult(&b);
+ lua_pushnumber(L, (lua_Number)n); /* number of substitutions */
+ return 2;
+}
+
+/* }====================================================== */
+
+
+/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
+#define MAX_ITEM 512
+/* maximum size of each format specification (such as '%-099.99d') */
+#define MAX_FORMAT 20
+
+
+static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
+ size_t l;
+ const char *s = luaL_checklstring(L, arg, &l);
+ luaL_putchar(b, '"');
+ while (l--) {
+ switch (*s) {
+ case '"': case '\\': case '\n': {
+ luaL_putchar(b, '\\');
+ luaL_putchar(b, *s);
+ break;
+ }
+ case '\0': {
+ luaL_addlstring(b, "\\000", 4);
+ break;
+ }
+ default: {
+ luaL_putchar(b, *s);
+ break;
+ }
+ }
+ s++;
+ }
+ luaL_putchar(b, '"');
+}
+
+
+static const char *scanformat (lua_State *L, const char *strfrmt,
+ char *form, int *hasprecision) {
+ const char *p = strfrmt;
+ while (strchr("-+ #0", *p)) p++; /* skip flags */
+ if (isdigit(uchar(*p))) p++; /* skip width */
+ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
+ if (*p == '.') {
+ p++;
+ *hasprecision = 1;
+ if (isdigit(uchar(*p))) p++; /* skip precision */
+ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
+ }
+ if (isdigit(uchar(*p)))
+ luaL_error(L, "invalid format (width or precision too long)");
+ if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */
+ luaL_error(L, "invalid format (too long)");
+ form[0] = '%';
+ strncpy(form+1, strfrmt, p-strfrmt+1);
+ form[p-strfrmt+2] = 0;
+ return p;
+}
+
+
+static int str_format (lua_State *L) {
+ int arg = 1;
+ size_t sfl;
+ const char *strfrmt = luaL_checklstring(L, arg, &sfl);
+ const char *strfrmt_end = strfrmt+sfl;
+ luaL_Buffer b;
+ luaL_buffinit(L, &b);
+ while (strfrmt < strfrmt_end) {
+ if (*strfrmt != '%')
+ luaL_putchar(&b, *strfrmt++);
+ else if (*++strfrmt == '%')
+ luaL_putchar(&b, *strfrmt++); /* %% */
+ else { /* format item */
+ char form[MAX_FORMAT]; /* to store the format (`%...') */
+ char buff[MAX_ITEM]; /* to store the formatted item */
+ int hasprecision = 0;
+ if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$')
+ return luaL_error(L, "obsolete option (d$) to `format'");
+ arg++;
+ strfrmt = scanformat(L, strfrmt, form, &hasprecision);
+ switch (*strfrmt++) {
+ case 'c': case 'd': case 'i': {
+ sprintf(buff, form, luaL_checkint(L, arg));
+ break;
+ }
+ case 'o': case 'u': case 'x': case 'X': {
+ sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg)));
+ break;
+ }
+ case 'e': case 'E': case 'f':
+ case 'g': case 'G': {
+ sprintf(buff, form, luaL_checknumber(L, arg));
+ break;
+ }
+ case 'q': {
+ luaI_addquoted(L, &b, arg);
+ continue; /* skip the `addsize' at the end */
+ }
+ case 's': {
+ size_t l;
+ const char *s = luaL_checklstring(L, arg, &l);
+ if (!hasprecision && l >= 100) {
+ /* no precision and string is too long to be formatted;
+ keep original string */
+ lua_pushvalue(L, arg);
+ luaL_addvalue(&b);
+ continue; /* skip the `addsize' at the end */
+ }
+ else {
+ sprintf(buff, form, s);
+ break;
+ }
+ }
+ default: { /* also treat cases `pnLlh' */
+ return luaL_error(L, "invalid option to `format'");
+ }
+ }
+ luaL_addlstring(&b, buff, strlen(buff));
+ }
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+static const luaL_reg strlib[] = {
+ {"len", str_len},
+ {"sub", str_sub},
+ {"lower", str_lower},
+ {"upper", str_upper},
+ {"char", str_char},
+ {"rep", str_rep},
+ {"byte", str_byte},
+ {"format", str_format},
+ {"dump", str_dump},
+ {"find", str_find},
+ {"gfind", gfind},
+ {"gsub", str_gsub},
+ {NULL, NULL}
+};
+
+
+/*
+** Open string library
+*/
+LUALIB_API int luaopen_string (lua_State *L) {
+ luaL_openlib(L, LUA_STRLIBNAME, strlib, 0);
+ return 1;
+}
+
diff --git a/lib/lua/src/LuaLib/ltablib.c b/lib/lua/src/LuaLib/ltablib.c index 165f8b1..fc6c380 100644 --- a/lib/lua/src/LuaLib/ltablib.c +++ b/lib/lua/src/LuaLib/ltablib.c @@ -1,250 +1,250 @@ -/* -** $Id: ltablib.c,v 1.2 2003-12-11 16:53:32 pixel Exp $ -** Library for Table Manipulation -** See Copyright Notice in lua.h -*/ - - -#include <stddef.h> - -#define ltablib_c - -#include "lua.h" - -#include "lauxlib.h" -#include "lualib.h" - - -#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n)) - - -static int luaB_foreachi (lua_State *L) { - int i; - int n = aux_getn(L, 1); - luaL_checktype(L, 2, LUA_TFUNCTION); - for (i=1; i<=n; i++) { - lua_pushvalue(L, 2); /* function */ - lua_pushnumber(L, (lua_Number)i); /* 1st argument */ - lua_rawgeti(L, 1, i); /* 2nd argument */ - lua_call(L, 2, 1); - if (!lua_isnil(L, -1)) - return 1; - lua_pop(L, 1); /* remove nil result */ - } - return 0; -} - - -static int luaB_foreach (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_pushnil(L); /* first key */ - for (;;) { - if (lua_next(L, 1) == 0) - return 0; - lua_pushvalue(L, 2); /* function */ - lua_pushvalue(L, -3); /* key */ - lua_pushvalue(L, -3); /* value */ - lua_call(L, 2, 1); - if (!lua_isnil(L, -1)) - return 1; - lua_pop(L, 2); /* remove value and result */ - } -} - - -static int luaB_getn (lua_State *L) { - lua_pushnumber(L, (lua_Number)aux_getn(L, 1)); - return 1; -} - - -static int luaB_setn (lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_setn(L, 1, luaL_checkint(L, 2)); - return 0; -} - - -static int luaB_tinsert (lua_State *L) { - int v = lua_gettop(L); /* number of arguments */ - int n = aux_getn(L, 1) + 1; - int pos; /* where to insert new element */ - if (v == 2) /* called with only 2 arguments */ - pos = n; /* insert new element at the end */ - else { - pos = luaL_checkint(L, 2); /* 2nd argument is the position */ - if (pos > n) n = pos; /* `grow' array if necessary */ - v = 3; /* function may be called with more than 3 args */ - } - luaL_setn(L, 1, n); /* new size */ - while (--n >= pos) { /* move up elements */ - lua_rawgeti(L, 1, n); - lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */ - } - lua_pushvalue(L, v); - lua_rawseti(L, 1, pos); /* t[pos] = v */ - return 0; -} - - -static int luaB_tremove (lua_State *L) { - int n = aux_getn(L, 1); - int pos = luaL_optint(L, 2, n); - if (n <= 0) return 0; /* table is `empty' */ - luaL_setn(L, 1, n-1); /* t.n = n-1 */ - lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos<n; pos++) { - lua_rawgeti(L, 1, pos+1); - lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */ - } - lua_pushnil(L); - lua_rawseti(L, 1, n); /* t[n] = nil */ - return 1; -} - - -static int str_concat (lua_State *L) { - luaL_Buffer b; - size_t lsep; - const char *sep = luaL_optlstring(L, 2, "", &lsep); - int i = luaL_optint(L, 3, 1); - int n = luaL_optint(L, 4, 0); - luaL_checktype(L, 1, LUA_TTABLE); - if (n == 0) n = luaL_getn(L, 1); - luaL_buffinit(L, &b); - for (; i <= n; i++) { - lua_rawgeti(L, 1, i); - luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings"); - luaL_addvalue(&b); - if (i != n) - luaL_addlstring(&b, sep, lsep); - } - luaL_pushresult(&b); - return 1; -} - - - -/* -** {====================================================== -** Quicksort -** (based on `Algorithms in MODULA-3', Robert Sedgewick; -** Addison-Wesley, 1993.) -*/ - - -static void set2 (lua_State *L, int i, int j) { - lua_rawseti(L, 1, i); - lua_rawseti(L, 1, j); -} - -static int sort_comp (lua_State *L, int a, int b) { - if (!lua_isnil(L, 2)) { /* function? */ - int res; - lua_pushvalue(L, 2); - lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ - lua_call(L, 2, 1); - res = lua_toboolean(L, -1); - lua_pop(L, 1); - return res; - } - else /* a < b? */ - return lua_lessthan(L, a, b); -} - -static void auxsort (lua_State *L, int l, int u) { - while (l < u) { /* for tail recursion */ - int i, j; - /* sort elements a[l], a[(l+u)/2] and a[u] */ - lua_rawgeti(L, 1, l); - lua_rawgeti(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ - set2(L, l, u); /* swap a[l] - a[u] */ - else - lua_pop(L, 2); - if (u-l == 1) break; /* only 2 elements */ - i = (l+u)/2; - lua_rawgeti(L, 1, i); - lua_rawgeti(L, 1, l); - if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */ - set2(L, i, l); - else { - lua_pop(L, 1); /* remove a[l] */ - lua_rawgeti(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */ - set2(L, i, u); - else - lua_pop(L, 2); - } - if (u-l == 2) break; /* only 3 elements */ - lua_rawgeti(L, 1, i); /* Pivot */ - lua_pushvalue(L, -1); - lua_rawgeti(L, 1, u-1); - set2(L, i, u-1); - /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */ - i = l; j = u-1; - for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */ - /* repeat ++i until a[i] >= P */ - while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>u) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* repeat --j until a[j] <= P */ - while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j<l) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - if (j<i) { - lua_pop(L, 3); /* pop pivot, a[i], a[j] */ - break; - } - set2(L, i, j); - } - lua_rawgeti(L, 1, u-1); - lua_rawgeti(L, 1, i); - set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */ - /* a[l..i-1] <= a[i] == P <= a[i+1..u] */ - /* adjust so that smaller half is in [j..i] and larger one in [l..u] */ - if (i-l < u-i) { - j=l; i=i-1; l=i+2; - } - else { - j=i+1; i=u; u=j-2; - } - auxsort(L, j, i); /* call recursively the smaller one */ - } /* repeat the routine for the larger one */ -} - -static int luaB_sort (lua_State *L) { - int n = aux_getn(L, 1); - luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_settop(L, 2); /* make sure there is two arguments */ - auxsort(L, 1, n); - return 0; -} - -/* }====================================================== */ - - -static const luaL_reg tab_funcs[] = { - {"concat", str_concat}, - {"foreach", luaB_foreach}, - {"foreachi", luaB_foreachi}, - {"getn", luaB_getn}, - {"setn", luaB_setn}, - {"sort", luaB_sort}, - {"insert", luaB_tinsert}, - {"remove", luaB_tremove}, - {NULL, NULL} -}; - - -LUALIB_API int luaopen_table (lua_State *L) { - luaL_openlib(L, LUA_TABLIBNAME, tab_funcs, 0); - return 1; -} - +/*
+** $Id: ltablib.c,v 1.3 2004-11-27 21:35:21 pixel Exp $
+** Library for Table Manipulation
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stddef.h>
+
+#define ltablib_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))
+
+
+static int luaB_foreachi (lua_State *L) {
+ int i;
+ int n = aux_getn(L, 1);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ for (i=1; i<=n; i++) {
+ lua_pushvalue(L, 2); /* function */
+ lua_pushnumber(L, (lua_Number)i); /* 1st argument */
+ lua_rawgeti(L, 1, i); /* 2nd argument */
+ lua_call(L, 2, 1);
+ if (!lua_isnil(L, -1))
+ return 1;
+ lua_pop(L, 1); /* remove nil result */
+ }
+ return 0;
+}
+
+
+static int luaB_foreach (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ lua_pushnil(L); /* first key */
+ for (;;) {
+ if (lua_next(L, 1) == 0)
+ return 0;
+ lua_pushvalue(L, 2); /* function */
+ lua_pushvalue(L, -3); /* key */
+ lua_pushvalue(L, -3); /* value */
+ lua_call(L, 2, 1);
+ if (!lua_isnil(L, -1))
+ return 1;
+ lua_pop(L, 2); /* remove value and result */
+ }
+}
+
+
+static int luaB_getn (lua_State *L) {
+ lua_pushnumber(L, (lua_Number)aux_getn(L, 1));
+ return 1;
+}
+
+
+static int luaB_setn (lua_State *L) {
+ luaL_checktype(L, 1, LUA_TTABLE);
+ luaL_setn(L, 1, luaL_checkint(L, 2));
+ return 0;
+}
+
+
+static int luaB_tinsert (lua_State *L) {
+ int v = lua_gettop(L); /* number of arguments */
+ int n = aux_getn(L, 1) + 1;
+ int pos; /* where to insert new element */
+ if (v == 2) /* called with only 2 arguments */
+ pos = n; /* insert new element at the end */
+ else {
+ pos = luaL_checkint(L, 2); /* 2nd argument is the position */
+ if (pos > n) n = pos; /* `grow' array if necessary */
+ v = 3; /* function may be called with more than 3 args */
+ }
+ luaL_setn(L, 1, n); /* new size */
+ while (--n >= pos) { /* move up elements */
+ lua_rawgeti(L, 1, n);
+ lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */
+ }
+ lua_pushvalue(L, v);
+ lua_rawseti(L, 1, pos); /* t[pos] = v */
+ return 0;
+}
+
+
+static int luaB_tremove (lua_State *L) {
+ int n = aux_getn(L, 1);
+ int pos = luaL_optint(L, 2, n);
+ if (n <= 0) return 0; /* table is `empty' */
+ luaL_setn(L, 1, n-1); /* t.n = n-1 */
+ lua_rawgeti(L, 1, pos); /* result = t[pos] */
+ for ( ;pos<n; pos++) {
+ lua_rawgeti(L, 1, pos+1);
+ lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
+ }
+ lua_pushnil(L);
+ lua_rawseti(L, 1, n); /* t[n] = nil */
+ return 1;
+}
+
+
+static int str_concat (lua_State *L) {
+ luaL_Buffer b;
+ size_t lsep;
+ const char *sep = luaL_optlstring(L, 2, "", &lsep);
+ int i = luaL_optint(L, 3, 1);
+ int n = luaL_optint(L, 4, 0);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ if (n == 0) n = luaL_getn(L, 1);
+ luaL_buffinit(L, &b);
+ for (; i <= n; i++) {
+ lua_rawgeti(L, 1, i);
+ luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings");
+ luaL_addvalue(&b);
+ if (i != n)
+ luaL_addlstring(&b, sep, lsep);
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+
+
+/*
+** {======================================================
+** Quicksort
+** (based on `Algorithms in MODULA-3', Robert Sedgewick;
+** Addison-Wesley, 1993.)
+*/
+
+
+static void set2 (lua_State *L, int i, int j) {
+ lua_rawseti(L, 1, i);
+ lua_rawseti(L, 1, j);
+}
+
+static int sort_comp (lua_State *L, int a, int b) {
+ if (!lua_isnil(L, 2)) { /* function? */
+ int res;
+ lua_pushvalue(L, 2);
+ lua_pushvalue(L, a-1); /* -1 to compensate function */
+ lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
+ lua_call(L, 2, 1);
+ res = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+ return res;
+ }
+ else /* a < b? */
+ return lua_lessthan(L, a, b);
+}
+
+static void auxsort (lua_State *L, int l, int u) {
+ while (l < u) { /* for tail recursion */
+ int i, j;
+ /* sort elements a[l], a[(l+u)/2] and a[u] */
+ lua_rawgeti(L, 1, l);
+ lua_rawgeti(L, 1, u);
+ if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
+ set2(L, l, u); /* swap a[l] - a[u] */
+ else
+ lua_pop(L, 2);
+ if (u-l == 1) break; /* only 2 elements */
+ i = (l+u)/2;
+ lua_rawgeti(L, 1, i);
+ lua_rawgeti(L, 1, l);
+ if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
+ set2(L, i, l);
+ else {
+ lua_pop(L, 1); /* remove a[l] */
+ lua_rawgeti(L, 1, u);
+ if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
+ set2(L, i, u);
+ else
+ lua_pop(L, 2);
+ }
+ if (u-l == 2) break; /* only 3 elements */
+ lua_rawgeti(L, 1, i); /* Pivot */
+ lua_pushvalue(L, -1);
+ lua_rawgeti(L, 1, u-1);
+ set2(L, i, u-1);
+ /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
+ i = l; j = u-1;
+ for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
+ /* repeat ++i until a[i] >= P */
+ while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
+ if (i>u) luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[i] */
+ }
+ /* repeat --j until a[j] <= P */
+ while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
+ if (j<l) luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[j] */
+ }
+ if (j<i) {
+ lua_pop(L, 3); /* pop pivot, a[i], a[j] */
+ break;
+ }
+ set2(L, i, j);
+ }
+ lua_rawgeti(L, 1, u-1);
+ lua_rawgeti(L, 1, i);
+ set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
+ /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
+ /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
+ if (i-l < u-i) {
+ j=l; i=i-1; l=i+2;
+ }
+ else {
+ j=i+1; i=u; u=j-2;
+ }
+ auxsort(L, j, i); /* call recursively the smaller one */
+ } /* repeat the routine for the larger one */
+}
+
+static int luaB_sort (lua_State *L) {
+ int n = aux_getn(L, 1);
+ luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
+ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ lua_settop(L, 2); /* make sure there is two arguments */
+ auxsort(L, 1, n);
+ return 0;
+}
+
+/* }====================================================== */
+
+
+static const luaL_reg tab_funcs[] = {
+ {"concat", str_concat},
+ {"foreach", luaB_foreach},
+ {"foreachi", luaB_foreachi},
+ {"getn", luaB_getn},
+ {"setn", luaB_setn},
+ {"sort", luaB_sort},
+ {"insert", luaB_tinsert},
+ {"remove", luaB_tremove},
+ {NULL, NULL}
+};
+
+
+LUALIB_API int luaopen_table (lua_State *L) {
+ luaL_openlib(L, LUA_TABLIBNAME, tab_funcs, 0);
+ return 1;
+}
+
diff --git a/lib/lua/src/lapi.c b/lib/lua/src/lapi.c index 0473cab..48646b9 100644 --- a/lib/lua/src/lapi.c +++ b/lib/lua/src/lapi.c @@ -1,922 +1,922 @@ -/* -** $Id: lapi.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Lua API -** See Copyright Notice in lua.h -*/ - - -#include <assert.h> -#include <string.h> - -#define lapi_c - -#include "lua.h" - -#include "lapi.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lundump.h" -#include "lvm.h" - - -const char lua_ident[] = - "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" - "$Authors: " LUA_AUTHORS " $\n" - "$URL: www.lua.org $\n"; - - - -#ifndef api_check -#define api_check(L, o) /*{ assert(o); }*/ -#endif - -#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) - -#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} - - - - -static TObject *negindex (lua_State *L, int idx) { - if (idx > LUA_REGISTRYINDEX) { - api_check(L, idx != 0 && -idx <= L->top - L->base); - return L->top+idx; - } - else switch (idx) { /* pseudo-indices */ - case LUA_REGISTRYINDEX: return registry(L); - case LUA_GLOBALSINDEX: return gt(L); - default: { - TObject *func = (L->base - 1); - idx = LUA_GLOBALSINDEX - idx; - lua_assert(iscfunction(func)); - return (idx <= clvalue(func)->c.nupvalues) - ? &clvalue(func)->c.upvalue[idx-1] - : NULL; - } - } -} - - -static TObject *luaA_index (lua_State *L, int idx) { - if (idx > 0) { - api_check(L, idx <= L->top - L->base); - return L->base + idx - 1; - } - else { - TObject *o = negindex(L, idx); - api_check(L, o != NULL); - return o; - } -} - - -static TObject *luaA_indexAcceptable (lua_State *L, int idx) { - if (idx > 0) { - TObject *o = L->base+(idx-1); - api_check(L, idx <= L->stack_last - L->base); - if (o >= L->top) return NULL; - else return o; - } - else - return negindex(L, idx); -} - - -void luaA_pushobject (lua_State *L, const TObject *o) { - setobj2s(L->top, o); - incr_top(L); -} - - -LUA_API int lua_checkstack (lua_State *L, int size) { - int res; - lua_lock(L); - if ((L->top - L->base + size) > LUA_MAXCSTACK) - res = 0; /* stack overflow */ - else { - luaD_checkstack(L, size); - if (L->ci->top < L->top + size) - L->ci->top = L->top + size; - res = 1; - } - lua_unlock(L); - return res; -} - - -LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { - int i; - lua_lock(to); - api_checknelems(from, n); - from->top -= n; - for (i = 0; i < n; i++) { - setobj2s(to->top, from->top + i); - api_incr_top(to); - } - lua_unlock(to); -} - - -LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { - lua_CFunction old; - lua_lock(L); - old = G(L)->panic; - G(L)->panic = panicf; - lua_unlock(L); - return old; -} - - -LUA_API lua_State *lua_newthread (lua_State *L) { - lua_State *L1; - lua_lock(L); - luaC_checkGC(L); - L1 = luaE_newthread(L); - setthvalue(L->top, L1); - api_incr_top(L); - lua_unlock(L); - lua_userstateopen(L1); - return L1; -} - - - -/* -** basic stack manipulation -*/ - - -LUA_API int lua_gettop (lua_State *L) { - return (L->top - L->base); -} - - -LUA_API void lua_settop (lua_State *L, int idx) { - lua_lock(L); - if (idx >= 0) { - api_check(L, idx <= L->stack_last - L->base); - while (L->top < L->base + idx) - setnilvalue(L->top++); - L->top = L->base + idx; - } - else { - api_check(L, -(idx+1) <= (L->top - L->base)); - L->top += idx+1; /* `subtract' index (index is negative) */ - } - lua_unlock(L); -} - - -LUA_API void lua_remove (lua_State *L, int idx) { - StkId p; - lua_lock(L); - p = luaA_index(L, idx); - while (++p < L->top) setobjs2s(p-1, p); - L->top--; - lua_unlock(L); -} - - -LUA_API void lua_insert (lua_State *L, int idx) { - StkId p; - StkId q; - lua_lock(L); - p = luaA_index(L, idx); - for (q = L->top; q>p; q--) setobjs2s(q, q-1); - setobjs2s(p, L->top); - lua_unlock(L); -} - - -LUA_API void lua_replace (lua_State *L, int idx) { - lua_lock(L); - api_checknelems(L, 1); - setobj(luaA_index(L, idx), L->top - 1); /* write barrier */ - L->top--; - lua_unlock(L); -} - - -LUA_API void lua_pushvalue (lua_State *L, int idx) { - lua_lock(L); - setobj2s(L->top, luaA_index(L, idx)); - api_incr_top(L); - lua_unlock(L); -} - - - -/* -** access functions (stack -> C) -*/ - - -LUA_API int lua_type (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? LUA_TNONE : ttype(o); -} - - -LUA_API const char *lua_typename (lua_State *L, int t) { - UNUSED(L); - return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; -} - - -LUA_API int lua_iscfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL) ? 0 : iscfunction(o); -} - - -LUA_API int lua_isnumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && tonumber(o, &n)); -} - - -LUA_API int lua_isstring (lua_State *L, int idx) { - int t = lua_type(L, idx); - return (t == LUA_TSTRING || t == LUA_TNUMBER); -} - - -LUA_API int lua_isuserdata (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL && (ttisuserdata(o) || ttislightuserdata(o))); -} - - -LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { - StkId o1 = luaA_indexAcceptable(L, index1); - StkId o2 = luaA_indexAcceptable(L, index2); - return (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : luaO_rawequalObj(o1, o2); -} - - -LUA_API int lua_equal (lua_State *L, int index1, int index2) { - StkId o1, o2; - int i; - lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out of range */ - : equalobj(L, o1, o2); - lua_unlock(L); - return i; -} - - -LUA_API int lua_lessthan (lua_State *L, int index1, int index2) { - StkId o1, o2; - int i; - lua_lock(L); /* may call tag method */ - o1 = luaA_indexAcceptable(L, index1); - o2 = luaA_indexAcceptable(L, index2); - i = (o1 == NULL || o2 == NULL) ? 0 /* index out-of-range */ - : luaV_lessthan(L, o1, o2); - lua_unlock(L); - return i; -} - - - -LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { - TObject n; - const TObject *o = luaA_indexAcceptable(L, idx); - if (o != NULL && tonumber(o, &n)) - return nvalue(o); - else - return 0; -} - - -LUA_API int lua_toboolean (lua_State *L, int idx) { - const TObject *o = luaA_indexAcceptable(L, idx); - return (o != NULL) && !l_isfalse(o); -} - - -LUA_API const char *lua_tostring (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return NULL; - else if (ttisstring(o)) - return svalue(o); - else { - const char *s; - lua_lock(L); /* `luaV_tostring' may create a new string */ - s = (luaV_tostring(L, o) ? svalue(o) : NULL); - luaC_checkGC(L); - lua_unlock(L); - return s; - } -} - - -LUA_API size_t lua_strlen (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) - return 0; - else if (ttisstring(o)) - return tsvalue(o)->tsv.len; - else { - size_t l; - lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) ? tsvalue(o)->tsv.len : 0); - lua_unlock(L); - return l; - } -} - - -LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->c.f; -} - - -LUA_API void *lua_touserdata (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; - switch (ttype(o)) { - case LUA_TUSERDATA: return (uvalue(o) + 1); - case LUA_TLIGHTUSERDATA: return pvalue(o); - default: return NULL; - } -} - - -LUA_API lua_State *lua_tothread (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o); -} - - -LUA_API const void *lua_topointer (lua_State *L, int idx) { - StkId o = luaA_indexAcceptable(L, idx); - if (o == NULL) return NULL; - else { - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(o); - case LUA_TFUNCTION: return clvalue(o); - case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); - default: return NULL; - } - } -} - - - -/* -** push functions (C -> stack) -*/ - - -LUA_API void lua_pushnil (lua_State *L) { - lua_lock(L); - setnilvalue(L->top); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { - lua_lock(L); - setnvalue(L->top, n); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { - lua_lock(L); - luaC_checkGC(L); - setsvalue2s(L->top, luaS_newlstr(L, s, len)); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushstring (lua_State *L, const char *s) { - if (s == NULL) - lua_pushnil(L); - else - lua_pushlstring(L, s, strlen(s)); -} - - -LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, - va_list argp) { - const char *ret; - lua_lock(L); - luaC_checkGC(L); - ret = luaO_pushvfstring(L, fmt, argp); - lua_unlock(L); - return ret; -} - - -LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { - const char *ret; - va_list argp; - lua_lock(L); - luaC_checkGC(L); - va_start(argp, fmt); - ret = luaO_pushvfstring(L, fmt, argp); - va_end(argp); - lua_unlock(L); - return ret; -} - - -LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - Closure *cl; - lua_lock(L); - luaC_checkGC(L); - api_checknelems(L, n); - cl = luaF_newCclosure(L, n); - cl->c.f = fn; - L->top -= n; - while (n--) - setobj2n(&cl->c.upvalue[n], L->top+n); - setclvalue(L->top, cl); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushboolean (lua_State *L, int b) { - lua_lock(L); - setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { - lua_lock(L); - setpvalue(L->top, p); - api_incr_top(L); - lua_unlock(L); -} - - - -/* -** get functions (Lua -> stack) -*/ - - -LUA_API void lua_gettable (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = luaA_index(L, idx); - setobj2s(L->top - 1, luaV_gettable(L, t, L->top - 1, 0)); - lua_unlock(L); -} - - -LUA_API void lua_rawget (lua_State *L, int idx) { - StkId t; - lua_lock(L); - t = luaA_index(L, idx); - api_check(L, ttistable(t)); - setobj2s(L->top - 1, luaH_get(hvalue(t), L->top - 1)); - lua_unlock(L); -} - - -LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { - StkId o; - lua_lock(L); - o = luaA_index(L, idx); - api_check(L, ttistable(o)); - setobj2s(L->top, luaH_getnum(hvalue(o), n)); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_newtable (lua_State *L) { - lua_lock(L); - luaC_checkGC(L); - sethvalue(L->top, luaH_new(L, 0, 0)); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API int lua_getmetatable (lua_State *L, int objindex) { - const TObject *obj; - Table *mt = NULL; - int res; - lua_lock(L); - obj = luaA_indexAcceptable(L, objindex); - if (obj != NULL) { - switch (ttype(obj)) { - case LUA_TTABLE: - mt = hvalue(obj)->metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj)->uv.metatable; - break; - } - } - if (mt == NULL || mt == hvalue(defaultmeta(L))) - res = 0; - else { - sethvalue(L->top, mt); - api_incr_top(L); - res = 1; - } - lua_unlock(L); - return res; -} - - -LUA_API void lua_getfenv (lua_State *L, int idx) { - StkId o; - lua_lock(L); - o = luaA_index(L, idx); - setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); - api_incr_top(L); - lua_unlock(L); -} - - -/* -** set functions (stack -> Lua) -*/ - - -LUA_API void lua_settable (lua_State *L, int idx) { - StkId t; - lua_lock(L); - api_checknelems(L, 2); - t = luaA_index(L, idx); - luaV_settable(L, t, L->top - 2, L->top - 1); - L->top -= 2; /* pop index and value */ - lua_unlock(L); -} - - -LUA_API void lua_rawset (lua_State *L, int idx) { - StkId t; - lua_lock(L); - api_checknelems(L, 2); - t = luaA_index(L, idx); - api_check(L, ttistable(t)); - setobj2t(luaH_set(L, hvalue(t), L->top-2), L->top-1); /* write barrier */ - L->top -= 2; - lua_unlock(L); -} - - -LUA_API void lua_rawseti (lua_State *L, int idx, int n) { - StkId o; - lua_lock(L); - api_checknelems(L, 1); - o = luaA_index(L, idx); - api_check(L, ttistable(o)); - setobj2t(luaH_setnum(L, hvalue(o), n), L->top-1); /* write barrier */ - L->top--; - lua_unlock(L); -} - - -LUA_API int lua_setmetatable (lua_State *L, int objindex) { - TObject *obj, *mt; - int res = 1; - lua_lock(L); - api_checknelems(L, 1); - obj = luaA_index(L, objindex); - mt = (!ttisnil(L->top - 1)) ? L->top - 1 : defaultmeta(L); - api_check(L, ttistable(mt)); - switch (ttype(obj)) { - case LUA_TTABLE: { - hvalue(obj)->metatable = hvalue(mt); /* write barrier */ - break; - } - case LUA_TUSERDATA: { - uvalue(obj)->uv.metatable = hvalue(mt); /* write barrier */ - break; - } - default: { - res = 0; /* cannot set */ - break; - } - } - L->top--; - lua_unlock(L); - return res; -} - - -LUA_API int lua_setfenv (lua_State *L, int idx) { - StkId o; - int res = 0; - lua_lock(L); - api_checknelems(L, 1); - o = luaA_index(L, idx); - L->top--; - api_check(L, ttistable(L->top)); - if (isLfunction(o)) { - res = 1; - clvalue(o)->l.g = *(L->top); - } - lua_unlock(L); - return res; -} - - -/* -** `load' and `call' functions (run Lua code) -*/ - -LUA_API void lua_call (lua_State *L, int nargs, int nresults) { - StkId func; - lua_lock(L); - api_checknelems(L, nargs+1); - func = L->top - (nargs+1); - luaD_call(L, func, nresults); - lua_unlock(L); -} - - - -/* -** Execute a protected call. -*/ -struct CallS { /* data to `f_call' */ - StkId func; - int nresults; -}; - - -static void f_call (lua_State *L, void *ud) { - struct CallS *c = cast(struct CallS *, ud); - luaD_call(L, c->func, c->nresults); -} - - - -LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { - struct CallS c; - int status; - ptrdiff_t func; - lua_lock(L); - func = (errfunc == 0) ? 0 : savestack(L, luaA_index(L, errfunc)); - c.func = L->top - (nargs+1); /* function to be called */ - c.nresults = nresults; - status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); - lua_unlock(L); - return status; -} - - -/* -** Execute a protected C call. -*/ -struct CCallS { /* data to `f_Ccall' */ - lua_CFunction func; - void *ud; -}; - - -static void f_Ccall (lua_State *L, void *ud) { - struct CCallS *c = cast(struct CCallS *, ud); - Closure *cl; - cl = luaF_newCclosure(L, 0); - cl->c.f = c->func; - setclvalue(L->top, cl); /* push function */ - incr_top(L); - setpvalue(L->top, c->ud); /* push only argument */ - incr_top(L); - luaD_call(L, L->top - 2, 0); -} - - -LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) { - struct CCallS c; - int status; - lua_lock(L); - c.func = func; - c.ud = ud; - status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); - lua_unlock(L); - return status; -} - - -LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, - const char *chunkname) { - ZIO z; - int status; - int c; - lua_lock(L); - if (!chunkname) chunkname = "?"; - luaZ_init(&z, reader, data, chunkname); - c = luaZ_lookahead(&z); - status = luaD_protectedparser(L, &z, (c == LUA_SIGNATURE[0])); - lua_unlock(L); - return status; -} - - -LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { - int status; - TObject *o; - lua_lock(L); - api_checknelems(L, 1); - o = L->top - 1; - if (isLfunction(o) && clvalue(o)->l.nupvalues == 0) { - luaU_dump(L, clvalue(o)->l.p, writer, data); - status = 1; - } - else - status = 0; - lua_unlock(L); - return status; -} - - -/* -** Garbage-collection functions -*/ - -/* GC values are expressed in Kbytes: #bytes/2^10 */ -#define GCscalel(x) ((x)>>10) -#define GCscale(x) (cast(int, GCscalel(x))) -#define GCunscale(x) (cast(lu_mem, x)<<10) - -LUA_API int lua_getgcthreshold (lua_State *L) { - int threshold; - lua_lock(L); - threshold = GCscale(G(L)->GCthreshold); - lua_unlock(L); - return threshold; -} - -LUA_API int lua_getgccount (lua_State *L) { - int count; - lua_lock(L); - count = GCscale(G(L)->nblocks); - lua_unlock(L); - return count; -} - -LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) { - lua_lock(L); - if (cast(lu_mem, newthreshold) > GCscalel(MAX_LUMEM)) - G(L)->GCthreshold = MAX_LUMEM; - else - G(L)->GCthreshold = GCunscale(newthreshold); - luaC_checkGC(L); - lua_unlock(L); -} - - -/* -** miscellaneous functions -*/ - - -LUA_API const char *lua_version (void) { - return LUA_VERSION; -} - - -LUA_API int lua_error (lua_State *L) { - lua_lock(L); - api_checknelems(L, 1); - luaG_errormsg(L); - lua_unlock(L); - return 0; /* to avoid warnings */ -} - - -LUA_API int lua_next (lua_State *L, int idx) { - StkId t; - int more; - lua_lock(L); - t = luaA_index(L, idx); - api_check(L, ttistable(t)); - more = luaH_next(L, hvalue(t), L->top - 1); - if (more) { - api_incr_top(L); - } - else /* no more elements */ - L->top -= 1; /* remove key */ - lua_unlock(L); - return more; -} - - -LUA_API void lua_concat (lua_State *L, int n) { - lua_lock(L); - luaC_checkGC(L); - api_checknelems(L, n); - if (n >= 2) { - luaV_concat(L, n, L->top - L->base - 1); - L->top -= (n-1); - } - else if (n == 0) { /* push empty string */ - setsvalue2s(L->top, luaS_newlstr(L, NULL, 0)); - api_incr_top(L); - } - /* else n == 1; nothing to do */ - lua_unlock(L); -} - - -LUA_API void *lua_newuserdata (lua_State *L, size_t size) { - Udata *u; - lua_lock(L); - luaC_checkGC(L); - u = luaS_newudata(L, size); - setuvalue(L->top, u); - api_incr_top(L); - lua_unlock(L); - return u + 1; -} - - -LUA_API int lua_pushupvalues (lua_State *L) { - Closure *func; - int n, i; - lua_lock(L); - api_check(L, iscfunction(L->base - 1)); - func = clvalue(L->base - 1); - n = func->c.nupvalues; - luaD_checkstack(L, n + LUA_MINSTACK); - for (i=0; i<n; i++) { - setobj2s(L->top, &func->c.upvalue[i]); - L->top++; - } - lua_unlock(L); - return n; -} - - -static const char *aux_upvalue (lua_State *L, int funcindex, int n, - TObject **val) { - Closure *f; - StkId fi = luaA_index(L, funcindex); - if (!ttisfunction(fi)) return NULL; - f = clvalue(fi); - if (f->c.isC) { - if (n > f->c.nupvalues) return NULL; - *val = &f->c.upvalue[n-1]; - return ""; - } - else { - Proto *p = f->l.p; - if (n > p->sizeupvalues) return NULL; - *val = f->l.upvals[n-1]->v; - return getstr(p->upvalues[n-1]); - } -} - - -LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TObject *val; - lua_lock(L); - name = aux_upvalue(L, funcindex, n, &val); - if (name) { - setobj2s(L->top, val); - api_incr_top(L); - } - lua_unlock(L); - return name; -} - - -LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { - const char *name; - TObject *val; - lua_lock(L); - api_checknelems(L, 1); - name = aux_upvalue(L, funcindex, n, &val); - if (name) { - L->top--; - setobj(val, L->top); /* write barrier */ - } - lua_unlock(L); - return name; -} - +/*
+** $Id: lapi.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Lua API
+** See Copyright Notice in lua.h
+*/
+
+
+#include <assert.h>
+#include <string.h>
+
+#define lapi_c
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+
+
+const char lua_ident[] =
+ "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n"
+ "$Authors: " LUA_AUTHORS " $\n"
+ "$URL: www.lua.org $\n";
+
+
+
+#ifndef api_check
+#define api_check(L, o) /*{ assert(o); }*/
+#endif
+
+#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base))
+
+#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;}
+
+
+
+
+static TObject *negindex (lua_State *L, int idx) {
+ if (idx > LUA_REGISTRYINDEX) {
+ api_check(L, idx != 0 && -idx <= L->top - L->base);
+ return L->top+idx;
+ }
+ else switch (idx) { /* pseudo-indices */
+ case LUA_REGISTRYINDEX: return registry(L);
+ case LUA_GLOBALSINDEX: return gt(L);
+ default: {
+ TObject *func = (L->base - 1);
+ idx = LUA_GLOBALSINDEX - idx;
+ lua_assert(iscfunction(func));
+ return (idx <= clvalue(func)->c.nupvalues)
+ ? &clvalue(func)->c.upvalue[idx-1]
+ : NULL;
+ }
+ }
+}
+
+
+static TObject *luaA_index (lua_State *L, int idx) {
+ if (idx > 0) {
+ api_check(L, idx <= L->top - L->base);
+ return L->base + idx - 1;
+ }
+ else {
+ TObject *o = negindex(L, idx);
+ api_check(L, o != NULL);
+ return o;
+ }
+}
+
+
+static TObject *luaA_indexAcceptable (lua_State *L, int idx) {
+ if (idx > 0) {
+ TObject *o = L->base+(idx-1);
+ api_check(L, idx <= L->stack_last - L->base);
+ if (o >= L->top) return NULL;
+ else return o;
+ }
+ else
+ return negindex(L, idx);
+}
+
+
+void luaA_pushobject (lua_State *L, const TObject *o) {
+ setobj2s(L->top, o);
+ incr_top(L);
+}
+
+
+LUA_API int lua_checkstack (lua_State *L, int size) {
+ int res;
+ lua_lock(L);
+ if ((L->top - L->base + size) > LUA_MAXCSTACK)
+ res = 0; /* stack overflow */
+ else {
+ luaD_checkstack(L, size);
+ if (L->ci->top < L->top + size)
+ L->ci->top = L->top + size;
+ res = 1;
+ }
+ lua_unlock(L);
+ return res;
+}
+
+
+LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
+ int i;
+ lua_lock(to);
+ api_checknelems(from, n);
+ from->top -= n;
+ for (i = 0; i < n; i++) {
+ setobj2s(to->top, from->top + i);
+ api_incr_top(to);
+ }
+ lua_unlock(to);
+}
+
+
+LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
+ lua_CFunction old;
+ lua_lock(L);
+ old = G(L)->panic;
+ G(L)->panic = panicf;
+ lua_unlock(L);
+ return old;
+}
+
+
+LUA_API lua_State *lua_newthread (lua_State *L) {
+ lua_State *L1;
+ lua_lock(L);
+ luaC_checkGC(L);
+ L1 = luaE_newthread(L);
+ setthvalue(L->top, L1);
+ api_incr_top(L);
+ lua_unlock(L);
+ lua_userstateopen(L1);
+ return L1;
+}
+
+
+
+/*
+** basic stack manipulation
+*/
+
+
+LUA_API int lua_gettop (lua_State *L) {
+ return (L->top - L->base);
+}
+
+
+LUA_API void lua_settop (lua_State *L, int idx) {
+ lua_lock(L);
+ if (idx >= 0) {
+ api_check(L, idx <= L->stack_last - L->base);
+ while (L->top < L->base + idx)
+ setnilvalue(L->top++);
+ L->top = L->base + idx;
+ }
+ else {
+ api_check(L, -(idx+1) <= (L->top - L->base));
+ L->top += idx+1; /* `subtract' index (index is negative) */
+ }
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_remove (lua_State *L, int idx) {
+ StkId p;
+ lua_lock(L);
+ p = luaA_index(L, idx);
+ while (++p < L->top) setobjs2s(p-1, p);
+ L->top--;
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_insert (lua_State *L, int idx) {
+ StkId p;
+ StkId q;
+ lua_lock(L);
+ p = luaA_index(L, idx);
+ for (q = L->top; q>p; q--) setobjs2s(q, q-1);
+ setobjs2s(p, L->top);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_replace (lua_State *L, int idx) {
+ lua_lock(L);
+ api_checknelems(L, 1);
+ setobj(luaA_index(L, idx), L->top - 1); /* write barrier */
+ L->top--;
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushvalue (lua_State *L, int idx) {
+ lua_lock(L);
+ setobj2s(L->top, luaA_index(L, idx));
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+
+/*
+** access functions (stack -> C)
+*/
+
+
+LUA_API int lua_type (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ return (o == NULL) ? LUA_TNONE : ttype(o);
+}
+
+
+LUA_API const char *lua_typename (lua_State *L, int t) {
+ UNUSED(L);
+ return (t == LUA_TNONE) ? "no value" : luaT_typenames[t];
+}
+
+
+LUA_API int lua_iscfunction (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ return (o == NULL) ? 0 : iscfunction(o);
+}
+
+
+LUA_API int lua_isnumber (lua_State *L, int idx) {
+ TObject n;
+ const TObject *o = luaA_indexAcceptable(L, idx);
+ return (o != NULL && tonumber(o, &n));
+}
+
+
+LUA_API int lua_isstring (lua_State *L, int idx) {
+ int t = lua_type(L, idx);
+ return (t == LUA_TSTRING || t == LUA_TNUMBER);
+}
+
+
+LUA_API int lua_isuserdata (lua_State *L, int idx) {
+ const TObject *o = luaA_indexAcceptable(L, idx);
+ return (o != NULL && (ttisuserdata(o) || ttislightuserdata(o)));
+}
+
+
+LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
+ StkId o1 = luaA_indexAcceptable(L, index1);
+ StkId o2 = luaA_indexAcceptable(L, index2);
+ return (o1 == NULL || o2 == NULL) ? 0 /* index out of range */
+ : luaO_rawequalObj(o1, o2);
+}
+
+
+LUA_API int lua_equal (lua_State *L, int index1, int index2) {
+ StkId o1, o2;
+ int i;
+ lua_lock(L); /* may call tag method */
+ o1 = luaA_indexAcceptable(L, index1);
+ o2 = luaA_indexAcceptable(L, index2);
+ i = (o1 == NULL || o2 == NULL) ? 0 /* index out of range */
+ : equalobj(L, o1, o2);
+ lua_unlock(L);
+ return i;
+}
+
+
+LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
+ StkId o1, o2;
+ int i;
+ lua_lock(L); /* may call tag method */
+ o1 = luaA_indexAcceptable(L, index1);
+ o2 = luaA_indexAcceptable(L, index2);
+ i = (o1 == NULL || o2 == NULL) ? 0 /* index out-of-range */
+ : luaV_lessthan(L, o1, o2);
+ lua_unlock(L);
+ return i;
+}
+
+
+
+LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
+ TObject n;
+ const TObject *o = luaA_indexAcceptable(L, idx);
+ if (o != NULL && tonumber(o, &n))
+ return nvalue(o);
+ else
+ return 0;
+}
+
+
+LUA_API int lua_toboolean (lua_State *L, int idx) {
+ const TObject *o = luaA_indexAcceptable(L, idx);
+ return (o != NULL) && !l_isfalse(o);
+}
+
+
+LUA_API const char *lua_tostring (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ if (o == NULL)
+ return NULL;
+ else if (ttisstring(o))
+ return svalue(o);
+ else {
+ const char *s;
+ lua_lock(L); /* `luaV_tostring' may create a new string */
+ s = (luaV_tostring(L, o) ? svalue(o) : NULL);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return s;
+ }
+}
+
+
+LUA_API size_t lua_strlen (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ if (o == NULL)
+ return 0;
+ else if (ttisstring(o))
+ return tsvalue(o)->tsv.len;
+ else {
+ size_t l;
+ lua_lock(L); /* `luaV_tostring' may create a new string */
+ l = (luaV_tostring(L, o) ? tsvalue(o)->tsv.len : 0);
+ lua_unlock(L);
+ return l;
+ }
+}
+
+
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->c.f;
+}
+
+
+LUA_API void *lua_touserdata (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ if (o == NULL) return NULL;
+ switch (ttype(o)) {
+ case LUA_TUSERDATA: return (uvalue(o) + 1);
+ case LUA_TLIGHTUSERDATA: return pvalue(o);
+ default: return NULL;
+ }
+}
+
+
+LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o);
+}
+
+
+LUA_API const void *lua_topointer (lua_State *L, int idx) {
+ StkId o = luaA_indexAcceptable(L, idx);
+ if (o == NULL) return NULL;
+ else {
+ switch (ttype(o)) {
+ case LUA_TTABLE: return hvalue(o);
+ case LUA_TFUNCTION: return clvalue(o);
+ case LUA_TTHREAD: return thvalue(o);
+ case LUA_TUSERDATA:
+ case LUA_TLIGHTUSERDATA:
+ return lua_touserdata(L, idx);
+ default: return NULL;
+ }
+ }
+}
+
+
+
+/*
+** push functions (C -> stack)
+*/
+
+
+LUA_API void lua_pushnil (lua_State *L) {
+ lua_lock(L);
+ setnilvalue(L->top);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
+ lua_lock(L);
+ setnvalue(L->top, n);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
+ lua_lock(L);
+ luaC_checkGC(L);
+ setsvalue2s(L->top, luaS_newlstr(L, s, len));
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushstring (lua_State *L, const char *s) {
+ if (s == NULL)
+ lua_pushnil(L);
+ else
+ lua_pushlstring(L, s, strlen(s));
+}
+
+
+LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
+ va_list argp) {
+ const char *ret;
+ lua_lock(L);
+ luaC_checkGC(L);
+ ret = luaO_pushvfstring(L, fmt, argp);
+ lua_unlock(L);
+ return ret;
+}
+
+
+LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
+ const char *ret;
+ va_list argp;
+ lua_lock(L);
+ luaC_checkGC(L);
+ va_start(argp, fmt);
+ ret = luaO_pushvfstring(L, fmt, argp);
+ va_end(argp);
+ lua_unlock(L);
+ return ret;
+}
+
+
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
+ Closure *cl;
+ lua_lock(L);
+ luaC_checkGC(L);
+ api_checknelems(L, n);
+ cl = luaF_newCclosure(L, n);
+ cl->c.f = fn;
+ L->top -= n;
+ while (n--)
+ setobj2n(&cl->c.upvalue[n], L->top+n);
+ setclvalue(L->top, cl);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushboolean (lua_State *L, int b) {
+ lua_lock(L);
+ setbvalue(L->top, (b != 0)); /* ensure that true is 1 */
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
+ lua_lock(L);
+ setpvalue(L->top, p);
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+
+/*
+** get functions (Lua -> stack)
+*/
+
+
+LUA_API void lua_gettable (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ t = luaA_index(L, idx);
+ setobj2s(L->top - 1, luaV_gettable(L, t, L->top - 1, 0));
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_rawget (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ t = luaA_index(L, idx);
+ api_check(L, ttistable(t));
+ setobj2s(L->top - 1, luaH_get(hvalue(t), L->top - 1));
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_rawgeti (lua_State *L, int idx, int n) {
+ StkId o;
+ lua_lock(L);
+ o = luaA_index(L, idx);
+ api_check(L, ttistable(o));
+ setobj2s(L->top, luaH_getnum(hvalue(o), n));
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_newtable (lua_State *L) {
+ lua_lock(L);
+ luaC_checkGC(L);
+ sethvalue(L->top, luaH_new(L, 0, 0));
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+LUA_API int lua_getmetatable (lua_State *L, int objindex) {
+ const TObject *obj;
+ Table *mt = NULL;
+ int res;
+ lua_lock(L);
+ obj = luaA_indexAcceptable(L, objindex);
+ if (obj != NULL) {
+ switch (ttype(obj)) {
+ case LUA_TTABLE:
+ mt = hvalue(obj)->metatable;
+ break;
+ case LUA_TUSERDATA:
+ mt = uvalue(obj)->uv.metatable;
+ break;
+ }
+ }
+ if (mt == NULL || mt == hvalue(defaultmeta(L)))
+ res = 0;
+ else {
+ sethvalue(L->top, mt);
+ api_incr_top(L);
+ res = 1;
+ }
+ lua_unlock(L);
+ return res;
+}
+
+
+LUA_API void lua_getfenv (lua_State *L, int idx) {
+ StkId o;
+ lua_lock(L);
+ o = luaA_index(L, idx);
+ setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L));
+ api_incr_top(L);
+ lua_unlock(L);
+}
+
+
+/*
+** set functions (stack -> Lua)
+*/
+
+
+LUA_API void lua_settable (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ api_checknelems(L, 2);
+ t = luaA_index(L, idx);
+ luaV_settable(L, t, L->top - 2, L->top - 1);
+ L->top -= 2; /* pop index and value */
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_rawset (lua_State *L, int idx) {
+ StkId t;
+ lua_lock(L);
+ api_checknelems(L, 2);
+ t = luaA_index(L, idx);
+ api_check(L, ttistable(t));
+ setobj2t(luaH_set(L, hvalue(t), L->top-2), L->top-1); /* write barrier */
+ L->top -= 2;
+ lua_unlock(L);
+}
+
+
+LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
+ StkId o;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = luaA_index(L, idx);
+ api_check(L, ttistable(o));
+ setobj2t(luaH_setnum(L, hvalue(o), n), L->top-1); /* write barrier */
+ L->top--;
+ lua_unlock(L);
+}
+
+
+LUA_API int lua_setmetatable (lua_State *L, int objindex) {
+ TObject *obj, *mt;
+ int res = 1;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ obj = luaA_index(L, objindex);
+ mt = (!ttisnil(L->top - 1)) ? L->top - 1 : defaultmeta(L);
+ api_check(L, ttistable(mt));
+ switch (ttype(obj)) {
+ case LUA_TTABLE: {
+ hvalue(obj)->metatable = hvalue(mt); /* write barrier */
+ break;
+ }
+ case LUA_TUSERDATA: {
+ uvalue(obj)->uv.metatable = hvalue(mt); /* write barrier */
+ break;
+ }
+ default: {
+ res = 0; /* cannot set */
+ break;
+ }
+ }
+ L->top--;
+ lua_unlock(L);
+ return res;
+}
+
+
+LUA_API int lua_setfenv (lua_State *L, int idx) {
+ StkId o;
+ int res = 0;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = luaA_index(L, idx);
+ L->top--;
+ api_check(L, ttistable(L->top));
+ if (isLfunction(o)) {
+ res = 1;
+ clvalue(o)->l.g = *(L->top);
+ }
+ lua_unlock(L);
+ return res;
+}
+
+
+/*
+** `load' and `call' functions (run Lua code)
+*/
+
+LUA_API void lua_call (lua_State *L, int nargs, int nresults) {
+ StkId func;
+ lua_lock(L);
+ api_checknelems(L, nargs+1);
+ func = L->top - (nargs+1);
+ luaD_call(L, func, nresults);
+ lua_unlock(L);
+}
+
+
+
+/*
+** Execute a protected call.
+*/
+struct CallS { /* data to `f_call' */
+ StkId func;
+ int nresults;
+};
+
+
+static void f_call (lua_State *L, void *ud) {
+ struct CallS *c = cast(struct CallS *, ud);
+ luaD_call(L, c->func, c->nresults);
+}
+
+
+
+LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
+ struct CallS c;
+ int status;
+ ptrdiff_t func;
+ lua_lock(L);
+ func = (errfunc == 0) ? 0 : savestack(L, luaA_index(L, errfunc));
+ c.func = L->top - (nargs+1); /* function to be called */
+ c.nresults = nresults;
+ status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
+ lua_unlock(L);
+ return status;
+}
+
+
+/*
+** Execute a protected C call.
+*/
+struct CCallS { /* data to `f_Ccall' */
+ lua_CFunction func;
+ void *ud;
+};
+
+
+static void f_Ccall (lua_State *L, void *ud) {
+ struct CCallS *c = cast(struct CCallS *, ud);
+ Closure *cl;
+ cl = luaF_newCclosure(L, 0);
+ cl->c.f = c->func;
+ setclvalue(L->top, cl); /* push function */
+ incr_top(L);
+ setpvalue(L->top, c->ud); /* push only argument */
+ incr_top(L);
+ luaD_call(L, L->top - 2, 0);
+}
+
+
+LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) {
+ struct CCallS c;
+ int status;
+ lua_lock(L);
+ c.func = func;
+ c.ud = ud;
+ status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0);
+ lua_unlock(L);
+ return status;
+}
+
+
+LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data,
+ const char *chunkname) {
+ ZIO z;
+ int status;
+ int c;
+ lua_lock(L);
+ if (!chunkname) chunkname = "?";
+ luaZ_init(&z, reader, data, chunkname);
+ c = luaZ_lookahead(&z);
+ status = luaD_protectedparser(L, &z, (c == LUA_SIGNATURE[0]));
+ lua_unlock(L);
+ return status;
+}
+
+
+LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) {
+ int status;
+ TObject *o;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = L->top - 1;
+ if (isLfunction(o) && clvalue(o)->l.nupvalues == 0) {
+ luaU_dump(L, clvalue(o)->l.p, writer, data);
+ status = 1;
+ }
+ else
+ status = 0;
+ lua_unlock(L);
+ return status;
+}
+
+
+/*
+** Garbage-collection functions
+*/
+
+/* GC values are expressed in Kbytes: #bytes/2^10 */
+#define GCscalel(x) ((x)>>10)
+#define GCscale(x) (cast(int, GCscalel(x)))
+#define GCunscale(x) (cast(lu_mem, x)<<10)
+
+LUA_API int lua_getgcthreshold (lua_State *L) {
+ int threshold;
+ lua_lock(L);
+ threshold = GCscale(G(L)->GCthreshold);
+ lua_unlock(L);
+ return threshold;
+}
+
+LUA_API int lua_getgccount (lua_State *L) {
+ int count;
+ lua_lock(L);
+ count = GCscale(G(L)->nblocks);
+ lua_unlock(L);
+ return count;
+}
+
+LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) {
+ lua_lock(L);
+ if (cast(lu_mem, newthreshold) > GCscalel(MAX_LUMEM))
+ G(L)->GCthreshold = MAX_LUMEM;
+ else
+ G(L)->GCthreshold = GCunscale(newthreshold);
+ luaC_checkGC(L);
+ lua_unlock(L);
+}
+
+
+/*
+** miscellaneous functions
+*/
+
+
+LUA_API const char *lua_version (void) {
+ return LUA_VERSION;
+}
+
+
+LUA_API int lua_error (lua_State *L) {
+ lua_lock(L);
+ api_checknelems(L, 1);
+ luaG_errormsg(L);
+ lua_unlock(L);
+ return 0; /* to avoid warnings */
+}
+
+
+LUA_API int lua_next (lua_State *L, int idx) {
+ StkId t;
+ int more;
+ lua_lock(L);
+ t = luaA_index(L, idx);
+ api_check(L, ttistable(t));
+ more = luaH_next(L, hvalue(t), L->top - 1);
+ if (more) {
+ api_incr_top(L);
+ }
+ else /* no more elements */
+ L->top -= 1; /* remove key */
+ lua_unlock(L);
+ return more;
+}
+
+
+LUA_API void lua_concat (lua_State *L, int n) {
+ lua_lock(L);
+ luaC_checkGC(L);
+ api_checknelems(L, n);
+ if (n >= 2) {
+ luaV_concat(L, n, L->top - L->base - 1);
+ L->top -= (n-1);
+ }
+ else if (n == 0) { /* push empty string */
+ setsvalue2s(L->top, luaS_newlstr(L, NULL, 0));
+ api_incr_top(L);
+ }
+ /* else n == 1; nothing to do */
+ lua_unlock(L);
+}
+
+
+LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
+ Udata *u;
+ lua_lock(L);
+ luaC_checkGC(L);
+ u = luaS_newudata(L, size);
+ setuvalue(L->top, u);
+ api_incr_top(L);
+ lua_unlock(L);
+ return u + 1;
+}
+
+
+LUA_API int lua_pushupvalues (lua_State *L) {
+ Closure *func;
+ int n, i;
+ lua_lock(L);
+ api_check(L, iscfunction(L->base - 1));
+ func = clvalue(L->base - 1);
+ n = func->c.nupvalues;
+ luaD_checkstack(L, n + LUA_MINSTACK);
+ for (i=0; i<n; i++) {
+ setobj2s(L->top, &func->c.upvalue[i]);
+ L->top++;
+ }
+ lua_unlock(L);
+ return n;
+}
+
+
+static const char *aux_upvalue (lua_State *L, int funcindex, int n,
+ TObject **val) {
+ Closure *f;
+ StkId fi = luaA_index(L, funcindex);
+ if (!ttisfunction(fi)) return NULL;
+ f = clvalue(fi);
+ if (f->c.isC) {
+ if (n > f->c.nupvalues) return NULL;
+ *val = &f->c.upvalue[n-1];
+ return "";
+ }
+ else {
+ Proto *p = f->l.p;
+ if (n > p->sizeupvalues) return NULL;
+ *val = f->l.upvals[n-1]->v;
+ return getstr(p->upvalues[n-1]);
+ }
+}
+
+
+LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
+ const char *name;
+ TObject *val;
+ lua_lock(L);
+ name = aux_upvalue(L, funcindex, n, &val);
+ if (name) {
+ setobj2s(L->top, val);
+ api_incr_top(L);
+ }
+ lua_unlock(L);
+ return name;
+}
+
+
+LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
+ const char *name;
+ TObject *val;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ name = aux_upvalue(L, funcindex, n, &val);
+ if (name) {
+ L->top--;
+ setobj(val, L->top); /* write barrier */
+ }
+ lua_unlock(L);
+ return name;
+}
+
diff --git a/lib/lua/src/lcode.c b/lib/lua/src/lcode.c index fc4a146..a873ed8 100644 --- a/lib/lua/src/lcode.c +++ b/lib/lua/src/lcode.c @@ -1,714 +1,714 @@ -/* -** $Id: lcode.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Code generator for Lua -** See Copyright Notice in lua.h -*/ - - -#include <stdlib.h> - -#define lcode_c - -#include "lua.h" - -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "llex.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" -#include "ltable.h" - - -#define hasjumps(e) ((e)->t != (e)->f) - - -void luaK_nil (FuncState *fs, int from, int n) { - Instruction *previous; - if (fs->pc > fs->lasttarget && /* no jumps to current position? */ - GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pto = GETARG_B(*previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(*previous, from+n-1); - return; - } - } - luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ -} - - -int luaK_jump (FuncState *fs) { - int jpc = fs->jpc; /* save list of jumps to here */ - int j; - fs->jpc = NO_JUMP; - j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); - luaK_concat(fs, &j, jpc); /* keep them on hold */ - return j; -} - - -static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) { - luaK_codeABC(fs, op, A, B, C); - return luaK_jump(fs); -} - - -static void luaK_fixjump (FuncState *fs, int pc, int dest) { - Instruction *jmp = &fs->f->code[pc]; - int offset = dest-(pc+1); - lua_assert(dest != NO_JUMP); - if (abs(offset) > MAXARG_sBx) - luaX_syntaxerror(fs->ls, "control structure too long"); - SETARG_sBx(*jmp, offset); -} - - -/* -** returns current `pc' and marks it as a jump target (to avoid wrong -** optimizations with consecutive instructions not in the same basic block). -*/ -int luaK_getlabel (FuncState *fs) { - fs->lasttarget = fs->pc; - return fs->pc; -} - - -static int luaK_getjump (FuncState *fs, int pc) { - int offset = GETARG_sBx(fs->f->code[pc]); - if (offset == NO_JUMP) /* point to itself represents end of list */ - return NO_JUMP; /* end of list */ - else - return (pc+1)+offset; /* turn offset into absolute position */ -} - - -static Instruction *getjumpcontrol (FuncState *fs, int pc) { - Instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT)) - return pi-1; - else - return pi; -} - - -/* -** check whether list has any jump that do not produce a value -** (or produce an inverted value) -*/ -static int need_value (FuncState *fs, int list, int cond) { - for (; list != NO_JUMP; list = luaK_getjump(fs, list)) { - Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1; - } - return 0; /* not found */ -} - - -static void patchtestreg (Instruction *i, int reg) { - if (reg == NO_REG) reg = GETARG_B(*i); - SETARG_A(*i, reg); -} - - -static void luaK_patchlistaux (FuncState *fs, int list, - int ttarget, int treg, int ftarget, int freg, int dtarget) { - while (list != NO_JUMP) { - int next = luaK_getjump(fs, list); - Instruction *i = getjumpcontrol(fs, list); - if (GET_OPCODE(*i) != OP_TEST) { - lua_assert(dtarget != NO_JUMP); - luaK_fixjump(fs, list, dtarget); /* jump to default target */ - } - else { - if (GETARG_C(*i)) { - lua_assert(ttarget != NO_JUMP); - patchtestreg(i, treg); - luaK_fixjump(fs, list, ttarget); - } - else { - lua_assert(ftarget != NO_JUMP); - patchtestreg(i, freg); - luaK_fixjump(fs, list, ftarget); - } - } - list = next; - } -} - - -static void luaK_dischargejpc (FuncState *fs) { - luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc); - fs->jpc = NO_JUMP; -} - - -void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->pc) - luaK_patchtohere(fs, list); - else { - lua_assert(target < fs->pc); - luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); - } -} - - -void luaK_patchtohere (FuncState *fs, int list) { - luaK_getlabel(fs); - luaK_concat(fs, &fs->jpc, list); -} - - -void luaK_concat (FuncState *fs, int *l1, int l2) { - if (l2 == NO_JUMP) return; - else if (*l1 == NO_JUMP) - *l1 = l2; - else { - int list = *l1; - int next; - while ((next = luaK_getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - luaK_fixjump(fs, list, l2); - } -} - - -void luaK_checkstack (FuncState *fs, int n) { - int newstack = fs->freereg + n; - if (newstack > fs->f->maxstacksize) { - if (newstack >= MAXSTACK) - luaX_syntaxerror(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = cast(lu_byte, newstack); - } -} - - -void luaK_reserveregs (FuncState *fs, int n) { - luaK_checkstack(fs, n); - fs->freereg += n; -} - - -static void freereg (FuncState *fs, int reg) { - if (reg >= fs->nactvar && reg < MAXSTACK) { - fs->freereg--; - lua_assert(reg == fs->freereg); - } -} - - -static void freeexp (FuncState *fs, expdesc *e) { - if (e->k == VNONRELOC) - freereg(fs, e->info); -} - - -static int addk (FuncState *fs, TObject *k, TObject *v) { - const TObject *idx = luaH_get(fs->h, k); - if (ttisnumber(idx)) { - lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v)); - return cast(int, nvalue(idx)); - } - else { /* constant not found; create a new entry */ - Proto *f = fs->f; - luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject, - MAXARG_Bx, "constant table overflow"); - setobj2n(&f->k[fs->nk], v); - setnvalue(luaH_set(fs->L, fs->h, k), cast(lua_Number, fs->nk)); - return fs->nk++; - } -} - - -int luaK_stringK (FuncState *fs, TString *s) { - TObject o; - setsvalue(&o, s); - return addk(fs, &o, &o); -} - - -int luaK_numberK (FuncState *fs, lua_Number r) { - TObject o; - setnvalue(&o, r); - return addk(fs, &o, &o); -} - - -static int nil_constant (FuncState *fs) { - TObject k, v; - setnilvalue(&v); - sethvalue(&k, fs->h); /* cannot use nil as key; instead use table itself */ - return addk(fs, &k, &v); -} - - -void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) { - if (e->k == VCALL) { /* expression is an open function call? */ - SETARG_C(getcode(fs, e), nresults+1); - if (nresults == 1) { /* `regular' expression? */ - e->k = VNONRELOC; - e->info = GETARG_A(getcode(fs, e)); - } - } -} - - -void luaK_dischargevars (FuncState *fs, expdesc *e) { - switch (e->k) { - case VLOCAL: { - e->k = VNONRELOC; - break; - } - case VUPVAL: { - e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0); - e->k = VRELOCABLE; - break; - } - case VGLOBAL: { - e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info); - e->k = VRELOCABLE; - break; - } - case VINDEXED: { - freereg(fs, e->aux); - freereg(fs, e->info); - e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux); - e->k = VRELOCABLE; - break; - } - case VCALL: { - luaK_setcallreturns(fs, e, 1); - break; - } - default: break; /* there is one value available (somewhere) */ - } -} - - -static int code_label (FuncState *fs, int A, int b, int jump) { - luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); -} - - -static void discharge2reg (FuncState *fs, expdesc *e, int reg) { - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: { - luaK_nil(fs, reg, 1); - break; - } - case VFALSE: case VTRUE: { - luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); - break; - } - case VK: { - luaK_codeABx(fs, OP_LOADK, reg, e->info); - break; - } - case VRELOCABLE: { - Instruction *pc = &getcode(fs, e); - SETARG_A(*pc, reg); - break; - } - case VNONRELOC: { - if (reg != e->info) - luaK_codeABC(fs, OP_MOVE, reg, e->info, 0); - break; - } - default: { - lua_assert(e->k == VVOID || e->k == VJMP); - return; /* nothing to do... */ - } - } - e->info = reg; - e->k = VNONRELOC; -} - - -static void discharge2anyreg (FuncState *fs, expdesc *e) { - if (e->k != VNONRELOC) { - luaK_reserveregs(fs, 1); - discharge2reg(fs, e, fs->freereg-1); - } -} - - -static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) { - discharge2reg(fs, e, reg); - if (e->k == VJMP) - luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */ - if (hasjumps(e)) { - int final; /* position after whole expression */ - int p_f = NO_JUMP; /* position of an eventual LOAD false */ - int p_t = NO_JUMP; /* position of an eventual LOAD true */ - if (need_value(fs, e->t, 1) || need_value(fs, e->f, 0)) { - int fj = NO_JUMP; /* first jump (over LOAD ops.) */ - if (e->k != VJMP) - fj = luaK_jump(fs); - p_f = code_label(fs, reg, 0, 1); - p_t = code_label(fs, reg, 1, 0); - luaK_patchtohere(fs, fj); - } - final = luaK_getlabel(fs); - luaK_patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f); - luaK_patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t); - } - e->f = e->t = NO_JUMP; - e->info = reg; - e->k = VNONRELOC; -} - - -void luaK_exp2nextreg (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - freeexp(fs, e); - luaK_reserveregs(fs, 1); - luaK_exp2reg(fs, e, fs->freereg - 1); -} - - -int luaK_exp2anyreg (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - if (e->k == VNONRELOC) { - if (!hasjumps(e)) return e->info; /* exp is already in a register */ - if (e->info >= fs->nactvar) { /* reg. is not a local? */ - luaK_exp2reg(fs, e, e->info); /* put value on it */ - return e->info; - } - } - luaK_exp2nextreg(fs, e); /* default */ - return e->info; -} - - -void luaK_exp2val (FuncState *fs, expdesc *e) { - if (hasjumps(e)) - luaK_exp2anyreg(fs, e); - else - luaK_dischargevars(fs, e); -} - - -int luaK_exp2RK (FuncState *fs, expdesc *e) { - luaK_exp2val(fs, e); - switch (e->k) { - case VNIL: { - if (fs->nk + MAXSTACK <= MAXARG_C) { /* constant fit in argC? */ - e->info = nil_constant(fs); - e->k = VK; - return e->info + MAXSTACK; - } - else break; - } - case VK: { - if (e->info + MAXSTACK <= MAXARG_C) /* constant fit in argC? */ - return e->info + MAXSTACK; - else break; - } - default: break; - } - /* not a constant in the right range: put it in a register */ - return luaK_exp2anyreg(fs, e); -} - - -void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) { - switch (var->k) { - case VLOCAL: { - freeexp(fs, exp); - luaK_exp2reg(fs, exp, var->info); - return; - } - case VUPVAL: { - int e = luaK_exp2anyreg(fs, exp); - luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0); - break; - } - case VGLOBAL: { - int e = luaK_exp2anyreg(fs, exp); - luaK_codeABx(fs, OP_SETGLOBAL, e, var->info); - break; - } - case VINDEXED: { - int e = luaK_exp2RK(fs, exp); - luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e); - break; - } - default: { - lua_assert(0); /* invalid var kind to store */ - break; - } - } - freeexp(fs, exp); -} - - -void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { - int func; - luaK_exp2anyreg(fs, e); - freeexp(fs, e); - func = fs->freereg; - luaK_reserveregs(fs, 2); - luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key)); - freeexp(fs, key); - e->info = func; - e->k = VNONRELOC; -} - - -static void invertjump (FuncState *fs, expdesc *e) { - Instruction *pc = getjumpcontrol(fs, e->info); - lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) && - GET_OPCODE(*pc) != OP_TEST); - SETARG_A(*pc, !(GETARG_A(*pc))); -} - - -static int jumponcond (FuncState *fs, expdesc *e, int cond) { - if (e->k == VRELOCABLE) { - Instruction ie = getcode(fs, e); - if (GET_OPCODE(ie) == OP_NOT) { - fs->pc--; /* remove previous OP_NOT */ - return luaK_condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond); - } - /* else go through */ - } - discharge2anyreg(fs, e); - freeexp(fs, e); - return luaK_condjump(fs, OP_TEST, NO_REG, e->info, cond); -} - - -void luaK_goiftrue (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VK: case VTRUE: { - pc = NO_JUMP; /* always true; do nothing */ - break; - } - case VFALSE: { - pc = luaK_jump(fs); /* always jump */ - break; - } - case VJMP: { - invertjump(fs, e); - pc = e->info; - break; - } - default: { - pc = jumponcond(fs, e, 0); - break; - } - } - luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ -} - - -void luaK_goiffalse (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: case VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ - break; - } - case VTRUE: { - pc = luaK_jump(fs); /* always jump */ - break; - } - case VJMP: { - pc = e->info; - break; - } - default: { - pc = jumponcond(fs, e, 1); - break; - } - } - luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ -} - - -static void codenot (FuncState *fs, expdesc *e) { - luaK_dischargevars(fs, e); - switch (e->k) { - case VNIL: case VFALSE: { - e->k = VTRUE; - break; - } - case VK: case VTRUE: { - e->k = VFALSE; - break; - } - case VJMP: { - invertjump(fs, e); - break; - } - case VRELOCABLE: - case VNONRELOC: { - discharge2anyreg(fs, e); - freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0); - e->k = VRELOCABLE; - break; - } - default: { - lua_assert(0); /* cannot happen */ - break; - } - } - /* interchange true and false lists */ - { int temp = e->f; e->f = e->t; e->t = temp; } -} - - -void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - t->aux = luaK_exp2RK(fs, k); - t->k = VINDEXED; -} - - -void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { - if (op == OPR_MINUS) { - luaK_exp2val(fs, e); - if (e->k == VK && ttisnumber(&fs->f->k[e->info])) - e->info = luaK_numberK(fs, -nvalue(&fs->f->k[e->info])); - else { - luaK_exp2anyreg(fs, e); - freeexp(fs, e); - e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0); - e->k = VRELOCABLE; - } - } - else /* op == NOT */ - codenot(fs, e); -} - - -void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { - switch (op) { - case OPR_AND: { - luaK_goiftrue(fs, v); - luaK_patchtohere(fs, v->t); - v->t = NO_JUMP; - break; - } - case OPR_OR: { - luaK_goiffalse(fs, v); - luaK_patchtohere(fs, v->f); - v->f = NO_JUMP; - break; - } - case OPR_CONCAT: { - luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ - break; - } - default: { - luaK_exp2RK(fs, v); - break; - } - } -} - - -static void codebinop (FuncState *fs, expdesc *res, BinOpr op, - int o1, int o2) { - if (op <= OPR_POW) { /* arithmetic operator? */ - OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD); /* ORDER OP */ - res->info = luaK_codeABC(fs, opc, 0, o1, o2); - res->k = VRELOCABLE; - } - else { /* test operator */ - static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE}; - int cond = 1; - if (op >= OPR_GT) { /* `>' or `>='? */ - int temp; /* exchange args and replace by `<' or `<=' */ - temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ - } - else if (op == OPR_NE) cond = 0; - res->info = luaK_condjump(fs, ops[op - OPR_NE], cond, o1, o2); - res->k = VJMP; - } -} - - -void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { - switch (op) { - case OPR_AND: { - lua_assert(e1->t == NO_JUMP); /* list must be closed */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, &e1->f, e2->f); - e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t; - break; - } - case OPR_OR: { - lua_assert(e1->f == NO_JUMP); /* list must be closed */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, &e1->t, e2->t); - e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f; - break; - } - case OPR_CONCAT: { - luaK_exp2val(fs, e2); - if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1); - freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1->info); - e1->k = e2->k; e1->info = e2->info; - } - else { - luaK_exp2nextreg(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info); - e1->k = VRELOCABLE; - } - break; - } - default: { - int o1 = luaK_exp2RK(fs, e1); - int o2 = luaK_exp2RK(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - codebinop(fs, e1, op, o1, o2); - } - } -} - - -void luaK_fixline (FuncState *fs, int line) { - fs->f->lineinfo[fs->pc - 1] = line; -} - - -int luaK_code (FuncState *fs, Instruction i, int line) { - Proto *f = fs->f; - luaK_dischargejpc(fs); /* `pc' will change */ - /* put new instruction in code array */ - luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, - MAX_INT, "code size overflow"); - f->code[fs->pc] = i; - /* save corresponding line information */ - luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, - MAX_INT, "code size overflow"); - f->lineinfo[fs->pc] = line; - return fs->pc++; -} - - -int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { - lua_assert(getOpMode(o) == iABC); - return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); -} - - -int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { - lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); - return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); -} - +/*
+** $Id: lcode.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#define lcode_c
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "ltable.h"
+
+
+#define hasjumps(e) ((e)->t != (e)->f)
+
+
+void luaK_nil (FuncState *fs, int from, int n) {
+ Instruction *previous;
+ if (fs->pc > fs->lasttarget && /* no jumps to current position? */
+ GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) {
+ int pfrom = GETARG_A(*previous);
+ int pto = GETARG_B(*previous);
+ if (pfrom <= from && from <= pto+1) { /* can connect both? */
+ if (from+n-1 > pto)
+ SETARG_B(*previous, from+n-1);
+ return;
+ }
+ }
+ luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
+}
+
+
+int luaK_jump (FuncState *fs) {
+ int jpc = fs->jpc; /* save list of jumps to here */
+ int j;
+ fs->jpc = NO_JUMP;
+ j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
+ luaK_concat(fs, &j, jpc); /* keep them on hold */
+ return j;
+}
+
+
+static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) {
+ luaK_codeABC(fs, op, A, B, C);
+ return luaK_jump(fs);
+}
+
+
+static void luaK_fixjump (FuncState *fs, int pc, int dest) {
+ Instruction *jmp = &fs->f->code[pc];
+ int offset = dest-(pc+1);
+ lua_assert(dest != NO_JUMP);
+ if (abs(offset) > MAXARG_sBx)
+ luaX_syntaxerror(fs->ls, "control structure too long");
+ SETARG_sBx(*jmp, offset);
+}
+
+
+/*
+** returns current `pc' and marks it as a jump target (to avoid wrong
+** optimizations with consecutive instructions not in the same basic block).
+*/
+int luaK_getlabel (FuncState *fs) {
+ fs->lasttarget = fs->pc;
+ return fs->pc;
+}
+
+
+static int luaK_getjump (FuncState *fs, int pc) {
+ int offset = GETARG_sBx(fs->f->code[pc]);
+ if (offset == NO_JUMP) /* point to itself represents end of list */
+ return NO_JUMP; /* end of list */
+ else
+ return (pc+1)+offset; /* turn offset into absolute position */
+}
+
+
+static Instruction *getjumpcontrol (FuncState *fs, int pc) {
+ Instruction *pi = &fs->f->code[pc];
+ if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT))
+ return pi-1;
+ else
+ return pi;
+}
+
+
+/*
+** check whether list has any jump that do not produce a value
+** (or produce an inverted value)
+*/
+static int need_value (FuncState *fs, int list, int cond) {
+ for (; list != NO_JUMP; list = luaK_getjump(fs, list)) {
+ Instruction i = *getjumpcontrol(fs, list);
+ if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1;
+ }
+ return 0; /* not found */
+}
+
+
+static void patchtestreg (Instruction *i, int reg) {
+ if (reg == NO_REG) reg = GETARG_B(*i);
+ SETARG_A(*i, reg);
+}
+
+
+static void luaK_patchlistaux (FuncState *fs, int list,
+ int ttarget, int treg, int ftarget, int freg, int dtarget) {
+ while (list != NO_JUMP) {
+ int next = luaK_getjump(fs, list);
+ Instruction *i = getjumpcontrol(fs, list);
+ if (GET_OPCODE(*i) != OP_TEST) {
+ lua_assert(dtarget != NO_JUMP);
+ luaK_fixjump(fs, list, dtarget); /* jump to default target */
+ }
+ else {
+ if (GETARG_C(*i)) {
+ lua_assert(ttarget != NO_JUMP);
+ patchtestreg(i, treg);
+ luaK_fixjump(fs, list, ttarget);
+ }
+ else {
+ lua_assert(ftarget != NO_JUMP);
+ patchtestreg(i, freg);
+ luaK_fixjump(fs, list, ftarget);
+ }
+ }
+ list = next;
+ }
+}
+
+
+static void luaK_dischargejpc (FuncState *fs) {
+ luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc);
+ fs->jpc = NO_JUMP;
+}
+
+
+void luaK_patchlist (FuncState *fs, int list, int target) {
+ if (target == fs->pc)
+ luaK_patchtohere(fs, list);
+ else {
+ lua_assert(target < fs->pc);
+ luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
+ }
+}
+
+
+void luaK_patchtohere (FuncState *fs, int list) {
+ luaK_getlabel(fs);
+ luaK_concat(fs, &fs->jpc, list);
+}
+
+
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+ if (l2 == NO_JUMP) return;
+ else if (*l1 == NO_JUMP)
+ *l1 = l2;
+ else {
+ int list = *l1;
+ int next;
+ while ((next = luaK_getjump(fs, list)) != NO_JUMP) /* find last element */
+ list = next;
+ luaK_fixjump(fs, list, l2);
+ }
+}
+
+
+void luaK_checkstack (FuncState *fs, int n) {
+ int newstack = fs->freereg + n;
+ if (newstack > fs->f->maxstacksize) {
+ if (newstack >= MAXSTACK)
+ luaX_syntaxerror(fs->ls, "function or expression too complex");
+ fs->f->maxstacksize = cast(lu_byte, newstack);
+ }
+}
+
+
+void luaK_reserveregs (FuncState *fs, int n) {
+ luaK_checkstack(fs, n);
+ fs->freereg += n;
+}
+
+
+static void freereg (FuncState *fs, int reg) {
+ if (reg >= fs->nactvar && reg < MAXSTACK) {
+ fs->freereg--;
+ lua_assert(reg == fs->freereg);
+ }
+}
+
+
+static void freeexp (FuncState *fs, expdesc *e) {
+ if (e->k == VNONRELOC)
+ freereg(fs, e->info);
+}
+
+
+static int addk (FuncState *fs, TObject *k, TObject *v) {
+ const TObject *idx = luaH_get(fs->h, k);
+ if (ttisnumber(idx)) {
+ lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v));
+ return cast(int, nvalue(idx));
+ }
+ else { /* constant not found; create a new entry */
+ Proto *f = fs->f;
+ luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject,
+ MAXARG_Bx, "constant table overflow");
+ setobj2n(&f->k[fs->nk], v);
+ setnvalue(luaH_set(fs->L, fs->h, k), cast(lua_Number, fs->nk));
+ return fs->nk++;
+ }
+}
+
+
+int luaK_stringK (FuncState *fs, TString *s) {
+ TObject o;
+ setsvalue(&o, s);
+ return addk(fs, &o, &o);
+}
+
+
+int luaK_numberK (FuncState *fs, lua_Number r) {
+ TObject o;
+ setnvalue(&o, r);
+ return addk(fs, &o, &o);
+}
+
+
+static int nil_constant (FuncState *fs) {
+ TObject k, v;
+ setnilvalue(&v);
+ sethvalue(&k, fs->h); /* cannot use nil as key; instead use table itself */
+ return addk(fs, &k, &v);
+}
+
+
+void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
+ if (e->k == VCALL) { /* expression is an open function call? */
+ SETARG_C(getcode(fs, e), nresults+1);
+ if (nresults == 1) { /* `regular' expression? */
+ e->k = VNONRELOC;
+ e->info = GETARG_A(getcode(fs, e));
+ }
+ }
+}
+
+
+void luaK_dischargevars (FuncState *fs, expdesc *e) {
+ switch (e->k) {
+ case VLOCAL: {
+ e->k = VNONRELOC;
+ break;
+ }
+ case VUPVAL: {
+ e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0);
+ e->k = VRELOCABLE;
+ break;
+ }
+ case VGLOBAL: {
+ e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info);
+ e->k = VRELOCABLE;
+ break;
+ }
+ case VINDEXED: {
+ freereg(fs, e->aux);
+ freereg(fs, e->info);
+ e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux);
+ e->k = VRELOCABLE;
+ break;
+ }
+ case VCALL: {
+ luaK_setcallreturns(fs, e, 1);
+ break;
+ }
+ default: break; /* there is one value available (somewhere) */
+ }
+}
+
+
+static int code_label (FuncState *fs, int A, int b, int jump) {
+ luaK_getlabel(fs); /* those instructions may be jump targets */
+ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
+}
+
+
+static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: {
+ luaK_nil(fs, reg, 1);
+ break;
+ }
+ case VFALSE: case VTRUE: {
+ luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
+ break;
+ }
+ case VK: {
+ luaK_codeABx(fs, OP_LOADK, reg, e->info);
+ break;
+ }
+ case VRELOCABLE: {
+ Instruction *pc = &getcode(fs, e);
+ SETARG_A(*pc, reg);
+ break;
+ }
+ case VNONRELOC: {
+ if (reg != e->info)
+ luaK_codeABC(fs, OP_MOVE, reg, e->info, 0);
+ break;
+ }
+ default: {
+ lua_assert(e->k == VVOID || e->k == VJMP);
+ return; /* nothing to do... */
+ }
+ }
+ e->info = reg;
+ e->k = VNONRELOC;
+}
+
+
+static void discharge2anyreg (FuncState *fs, expdesc *e) {
+ if (e->k != VNONRELOC) {
+ luaK_reserveregs(fs, 1);
+ discharge2reg(fs, e, fs->freereg-1);
+ }
+}
+
+
+static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) {
+ discharge2reg(fs, e, reg);
+ if (e->k == VJMP)
+ luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */
+ if (hasjumps(e)) {
+ int final; /* position after whole expression */
+ int p_f = NO_JUMP; /* position of an eventual LOAD false */
+ int p_t = NO_JUMP; /* position of an eventual LOAD true */
+ if (need_value(fs, e->t, 1) || need_value(fs, e->f, 0)) {
+ int fj = NO_JUMP; /* first jump (over LOAD ops.) */
+ if (e->k != VJMP)
+ fj = luaK_jump(fs);
+ p_f = code_label(fs, reg, 0, 1);
+ p_t = code_label(fs, reg, 1, 0);
+ luaK_patchtohere(fs, fj);
+ }
+ final = luaK_getlabel(fs);
+ luaK_patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f);
+ luaK_patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t);
+ }
+ e->f = e->t = NO_JUMP;
+ e->info = reg;
+ e->k = VNONRELOC;
+}
+
+
+void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
+ luaK_dischargevars(fs, e);
+ freeexp(fs, e);
+ luaK_reserveregs(fs, 1);
+ luaK_exp2reg(fs, e, fs->freereg - 1);
+}
+
+
+int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
+ luaK_dischargevars(fs, e);
+ if (e->k == VNONRELOC) {
+ if (!hasjumps(e)) return e->info; /* exp is already in a register */
+ if (e->info >= fs->nactvar) { /* reg. is not a local? */
+ luaK_exp2reg(fs, e, e->info); /* put value on it */
+ return e->info;
+ }
+ }
+ luaK_exp2nextreg(fs, e); /* default */
+ return e->info;
+}
+
+
+void luaK_exp2val (FuncState *fs, expdesc *e) {
+ if (hasjumps(e))
+ luaK_exp2anyreg(fs, e);
+ else
+ luaK_dischargevars(fs, e);
+}
+
+
+int luaK_exp2RK (FuncState *fs, expdesc *e) {
+ luaK_exp2val(fs, e);
+ switch (e->k) {
+ case VNIL: {
+ if (fs->nk + MAXSTACK <= MAXARG_C) { /* constant fit in argC? */
+ e->info = nil_constant(fs);
+ e->k = VK;
+ return e->info + MAXSTACK;
+ }
+ else break;
+ }
+ case VK: {
+ if (e->info + MAXSTACK <= MAXARG_C) /* constant fit in argC? */
+ return e->info + MAXSTACK;
+ else break;
+ }
+ default: break;
+ }
+ /* not a constant in the right range: put it in a register */
+ return luaK_exp2anyreg(fs, e);
+}
+
+
+void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) {
+ switch (var->k) {
+ case VLOCAL: {
+ freeexp(fs, exp);
+ luaK_exp2reg(fs, exp, var->info);
+ return;
+ }
+ case VUPVAL: {
+ int e = luaK_exp2anyreg(fs, exp);
+ luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0);
+ break;
+ }
+ case VGLOBAL: {
+ int e = luaK_exp2anyreg(fs, exp);
+ luaK_codeABx(fs, OP_SETGLOBAL, e, var->info);
+ break;
+ }
+ case VINDEXED: {
+ int e = luaK_exp2RK(fs, exp);
+ luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e);
+ break;
+ }
+ default: {
+ lua_assert(0); /* invalid var kind to store */
+ break;
+ }
+ }
+ freeexp(fs, exp);
+}
+
+
+void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+ int func;
+ luaK_exp2anyreg(fs, e);
+ freeexp(fs, e);
+ func = fs->freereg;
+ luaK_reserveregs(fs, 2);
+ luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key));
+ freeexp(fs, key);
+ e->info = func;
+ e->k = VNONRELOC;
+}
+
+
+static void invertjump (FuncState *fs, expdesc *e) {
+ Instruction *pc = getjumpcontrol(fs, e->info);
+ lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) &&
+ GET_OPCODE(*pc) != OP_TEST);
+ SETARG_A(*pc, !(GETARG_A(*pc)));
+}
+
+
+static int jumponcond (FuncState *fs, expdesc *e, int cond) {
+ if (e->k == VRELOCABLE) {
+ Instruction ie = getcode(fs, e);
+ if (GET_OPCODE(ie) == OP_NOT) {
+ fs->pc--; /* remove previous OP_NOT */
+ return luaK_condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond);
+ }
+ /* else go through */
+ }
+ discharge2anyreg(fs, e);
+ freeexp(fs, e);
+ return luaK_condjump(fs, OP_TEST, NO_REG, e->info, cond);
+}
+
+
+void luaK_goiftrue (FuncState *fs, expdesc *e) {
+ int pc; /* pc of last jump */
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VK: case VTRUE: {
+ pc = NO_JUMP; /* always true; do nothing */
+ break;
+ }
+ case VFALSE: {
+ pc = luaK_jump(fs); /* always jump */
+ break;
+ }
+ case VJMP: {
+ invertjump(fs, e);
+ pc = e->info;
+ break;
+ }
+ default: {
+ pc = jumponcond(fs, e, 0);
+ break;
+ }
+ }
+ luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
+}
+
+
+void luaK_goiffalse (FuncState *fs, expdesc *e) {
+ int pc; /* pc of last jump */
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: case VFALSE: {
+ pc = NO_JUMP; /* always false; do nothing */
+ break;
+ }
+ case VTRUE: {
+ pc = luaK_jump(fs); /* always jump */
+ break;
+ }
+ case VJMP: {
+ pc = e->info;
+ break;
+ }
+ default: {
+ pc = jumponcond(fs, e, 1);
+ break;
+ }
+ }
+ luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
+}
+
+
+static void codenot (FuncState *fs, expdesc *e) {
+ luaK_dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: case VFALSE: {
+ e->k = VTRUE;
+ break;
+ }
+ case VK: case VTRUE: {
+ e->k = VFALSE;
+ break;
+ }
+ case VJMP: {
+ invertjump(fs, e);
+ break;
+ }
+ case VRELOCABLE:
+ case VNONRELOC: {
+ discharge2anyreg(fs, e);
+ freeexp(fs, e);
+ e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0);
+ e->k = VRELOCABLE;
+ break;
+ }
+ default: {
+ lua_assert(0); /* cannot happen */
+ break;
+ }
+ }
+ /* interchange true and false lists */
+ { int temp = e->f; e->f = e->t; e->t = temp; }
+}
+
+
+void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+ t->aux = luaK_exp2RK(fs, k);
+ t->k = VINDEXED;
+}
+
+
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+ if (op == OPR_MINUS) {
+ luaK_exp2val(fs, e);
+ if (e->k == VK && ttisnumber(&fs->f->k[e->info]))
+ e->info = luaK_numberK(fs, -nvalue(&fs->f->k[e->info]));
+ else {
+ luaK_exp2anyreg(fs, e);
+ freeexp(fs, e);
+ e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0);
+ e->k = VRELOCABLE;
+ }
+ }
+ else /* op == NOT */
+ codenot(fs, e);
+}
+
+
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
+ switch (op) {
+ case OPR_AND: {
+ luaK_goiftrue(fs, v);
+ luaK_patchtohere(fs, v->t);
+ v->t = NO_JUMP;
+ break;
+ }
+ case OPR_OR: {
+ luaK_goiffalse(fs, v);
+ luaK_patchtohere(fs, v->f);
+ v->f = NO_JUMP;
+ break;
+ }
+ case OPR_CONCAT: {
+ luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
+ break;
+ }
+ default: {
+ luaK_exp2RK(fs, v);
+ break;
+ }
+ }
+}
+
+
+static void codebinop (FuncState *fs, expdesc *res, BinOpr op,
+ int o1, int o2) {
+ if (op <= OPR_POW) { /* arithmetic operator? */
+ OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD); /* ORDER OP */
+ res->info = luaK_codeABC(fs, opc, 0, o1, o2);
+ res->k = VRELOCABLE;
+ }
+ else { /* test operator */
+ static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE};
+ int cond = 1;
+ if (op >= OPR_GT) { /* `>' or `>='? */
+ int temp; /* exchange args and replace by `<' or `<=' */
+ temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
+ }
+ else if (op == OPR_NE) cond = 0;
+ res->info = luaK_condjump(fs, ops[op - OPR_NE], cond, o1, o2);
+ res->k = VJMP;
+ }
+}
+
+
+void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
+ switch (op) {
+ case OPR_AND: {
+ lua_assert(e1->t == NO_JUMP); /* list must be closed */
+ luaK_dischargevars(fs, e2);
+ luaK_concat(fs, &e1->f, e2->f);
+ e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t;
+ break;
+ }
+ case OPR_OR: {
+ lua_assert(e1->f == NO_JUMP); /* list must be closed */
+ luaK_dischargevars(fs, e2);
+ luaK_concat(fs, &e1->t, e2->t);
+ e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f;
+ break;
+ }
+ case OPR_CONCAT: {
+ luaK_exp2val(fs, e2);
+ if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
+ lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1);
+ freeexp(fs, e1);
+ SETARG_B(getcode(fs, e2), e1->info);
+ e1->k = e2->k; e1->info = e2->info;
+ }
+ else {
+ luaK_exp2nextreg(fs, e2);
+ freeexp(fs, e2);
+ freeexp(fs, e1);
+ e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info);
+ e1->k = VRELOCABLE;
+ }
+ break;
+ }
+ default: {
+ int o1 = luaK_exp2RK(fs, e1);
+ int o2 = luaK_exp2RK(fs, e2);
+ freeexp(fs, e2);
+ freeexp(fs, e1);
+ codebinop(fs, e1, op, o1, o2);
+ }
+ }
+}
+
+
+void luaK_fixline (FuncState *fs, int line) {
+ fs->f->lineinfo[fs->pc - 1] = line;
+}
+
+
+int luaK_code (FuncState *fs, Instruction i, int line) {
+ Proto *f = fs->f;
+ luaK_dischargejpc(fs); /* `pc' will change */
+ /* put new instruction in code array */
+ luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
+ MAX_INT, "code size overflow");
+ f->code[fs->pc] = i;
+ /* save corresponding line information */
+ luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
+ MAX_INT, "code size overflow");
+ f->lineinfo[fs->pc] = line;
+ return fs->pc++;
+}
+
+
+int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
+ lua_assert(getOpMode(o) == iABC);
+ return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
+}
+
+
+int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
+ lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
+ return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
+}
+
diff --git a/lib/lua/src/ldebug.c b/lib/lua/src/ldebug.c index c78ca4f..0b8e987 100644 --- a/lib/lua/src/ldebug.c +++ b/lib/lua/src/ldebug.c @@ -1,585 +1,585 @@ -/* -** $Id: ldebug.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Debug Interface -** See Copyright Notice in lua.h -*/ - - -#include <stdlib.h> -#include <string.h> - -#define ldebug_c - -#include "lua.h" - -#include "lapi.h" -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lvm.h" - - - -static const char *getfuncname (CallInfo *ci, const char **name); - - -#define isLua(ci) (!((ci)->state & CI_C)) - - -static int currentpc (CallInfo *ci) { - if (!isLua(ci)) return -1; /* function is not a Lua function? */ - if (ci->state & CI_HASFRAME) /* function has a frame? */ - ci->u.l.savedpc = *ci->u.l.pc; /* use `pc' from there */ - /* function's pc is saved */ - return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p); -} - - -static int currentline (CallInfo *ci) { - int pc = currentpc(ci); - if (pc < 0) - return -1; /* only active lua functions have current-line information */ - else - return getline(ci_func(ci)->l.p, pc); -} - - -void luaG_inithooks (lua_State *L) { - CallInfo *ci; - for (ci = L->ci; ci != L->base_ci; ci--) /* update all `savedpc's */ - currentpc(ci); - L->hookinit = 1; -} - - -/* -** this function can be called asynchronous (e.g. during a signal) -*/ -LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { - if (func == NULL || mask == 0) { /* turn off hooks? */ - mask = 0; - func = NULL; - } - L->hook = func; - L->basehookcount = count; - resethookcount(L); - L->hookmask = cast(lu_byte, mask); - L->hookinit = 0; - return 1; -} - - -LUA_API lua_Hook lua_gethook (lua_State *L) { - return L->hook; -} - - -LUA_API int lua_gethookmask (lua_State *L) { - return L->hookmask; -} - - -LUA_API int lua_gethookcount (lua_State *L) { - return L->basehookcount; -} - - -LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { - int status; - CallInfo *ci; - lua_lock(L); - for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { - level--; - if (!(ci->state & CI_C)) /* Lua function? */ - level -= ci->u.l.tailcalls; /* skip lost tail calls */ - } - if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */ - else if (level < 0) { /* level is of a lost tail call */ - status = 1; - ar->i_ci = 0; - } - else { - status = 1; - ar->i_ci = ci - L->base_ci; - } - lua_unlock(L); - return status; -} - - -static Proto *getluaproto (CallInfo *ci) { - return (isLua(ci) ? ci_func(ci)->l.p : NULL); -} - - -LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { - const char *name; - CallInfo *ci; - Proto *fp; - lua_lock(L); - name = NULL; - ci = L->base_ci + ar->i_ci; - fp = getluaproto(ci); - if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(ci)); - if (name) - luaA_pushobject(L, ci->base+(n-1)); /* push value */ - } - lua_unlock(L); - return name; -} - - -LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - const char *name; - CallInfo *ci; - Proto *fp; - lua_lock(L); - name = NULL; - ci = L->base_ci + ar->i_ci; - fp = getluaproto(ci); - L->top--; /* pop new value */ - if (fp) { /* is a Lua function? */ - name = luaF_getlocalname(fp, n, currentpc(ci)); - if (!name || name[0] == '(') /* `(' starts private locals */ - name = NULL; - else - setobjs2s(ci->base+(n-1), L->top); - } - lua_unlock(L); - return name; -} - - -static void funcinfo (lua_Debug *ar, StkId func) { - Closure *cl = clvalue(func); - if (cl->c.isC) { - ar->source = "=[C]"; - ar->linedefined = -1; - ar->what = "C"; - } - else { - ar->source = getstr(cl->l.p->source); - ar->linedefined = cl->l.p->lineDefined; - ar->what = (ar->linedefined == 0) ? "main" : "Lua"; - } - luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); -} - - -static const char *travglobals (lua_State *L, const TObject *o) { - Table *g = hvalue(gt(L)); - int i = sizenode(g); - while (i--) { - Node *n = gnode(g, i); - if (luaO_rawequalObj(o, gval(n)) && ttisstring(gkey(n))) - return getstr(tsvalue(gkey(n))); - } - return NULL; -} - - -static void info_tailcall (lua_State *L, lua_Debug *ar) { - ar->name = ar->namewhat = ""; - ar->what = "tail"; - ar->linedefined = ar->currentline = -1; - ar->source = "=(tail call)"; - luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); - ar->nups = 0; - setnilvalue(L->top); -} - - -static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - StkId f, CallInfo *ci) { - int status = 1; - for (; *what; what++) { - switch (*what) { - case 'S': { - funcinfo(ar, f); - break; - } - case 'l': { - ar->currentline = (ci) ? currentline(ci) : -1; - break; - } - case 'u': { - ar->nups = clvalue(f)->c.nupvalues; - break; - } - case 'n': { - ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL; - if (ar->namewhat == NULL) { - /* try to find a global name */ - if ((ar->name = travglobals(L, f)) != NULL) - ar->namewhat = "global"; - else ar->namewhat = ""; /* not found */ - } - break; - } - case 'f': { - setobj2s(L->top, f); - break; - } - default: status = 0; /* invalid option */ - } - } - return status; -} - - -LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { - int status = 1; - lua_lock(L); - if (*what == '>') { - StkId f = L->top - 1; - if (!ttisfunction(f)) - luaG_runerror(L, "value for `lua_getinfo' is not a function"); - status = auxgetinfo(L, what + 1, ar, f, NULL); - L->top--; /* pop function */ - } - else if (ar->i_ci != 0) { /* no tail call? */ - CallInfo *ci = L->base_ci + ar->i_ci; - lua_assert(ttisfunction(ci->base - 1)); - status = auxgetinfo(L, what, ar, ci->base - 1, ci); - } - else - info_tailcall(L, ar); - if (strchr(what, 'f')) incr_top(L); - lua_unlock(L); - return status; -} - - -/* -** {====================================================== -** Symbolic Execution and code checker -** ======================================================= -*/ - -#define check(x) if (!(x)) return 0; - -#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) - -#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) - - - -static int precheck (const Proto *pt) { - check(pt->maxstacksize <= MAXSTACK); - check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); - lua_assert(pt->numparams+pt->is_vararg <= pt->maxstacksize); - check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); - return 1; -} - - -static int checkopenop (const Proto *pt, int pc) { - Instruction i = pt->code[pc+1]; - switch (GET_OPCODE(i)) { - case OP_CALL: - case OP_TAILCALL: - case OP_RETURN: { - check(GETARG_B(i) == 0); - return 1; - } - case OP_SETLISTO: return 1; - default: return 0; /* invalid instruction after an open call */ - } -} - - -static int checkRK (const Proto *pt, int r) { - return (r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek)); -} - - -static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { - int pc; - int last; /* stores position of last instruction that changed `reg' */ - last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ - check(precheck(pt)); - for (pc = 0; pc < lastpc; pc++) { - const Instruction i = pt->code[pc]; - OpCode op = GET_OPCODE(i); - int a = GETARG_A(i); - int b = 0; - int c = 0; - checkreg(pt, a); - switch (getOpMode(op)) { - case iABC: { - b = GETARG_B(i); - c = GETARG_C(i); - if (testOpMode(op, OpModeBreg)) { - checkreg(pt, b); - } - else if (testOpMode(op, OpModeBrk)) - check(checkRK(pt, b)); - if (testOpMode(op, OpModeCrk)) - check(checkRK(pt, c)); - break; - } - case iABx: { - b = GETARG_Bx(i); - if (testOpMode(op, OpModeK)) check(b < pt->sizek); - break; - } - case iAsBx: { - b = GETARG_sBx(i); - break; - } - } - if (testOpMode(op, OpModesetA)) { - if (a == reg) last = pc; /* change register `a' */ - } - if (testOpMode(op, OpModeT)) { - check(pc+2 < pt->sizecode); /* check skip */ - check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); - } - switch (op) { - case OP_LOADBOOL: { - check(c == 0 || pc+2 < pt->sizecode); /* check its jump */ - break; - } - case OP_LOADNIL: { - if (a <= reg && reg <= b) - last = pc; /* set registers from `a' to `b' */ - break; - } - case OP_GETUPVAL: - case OP_SETUPVAL: { - check(b < pt->nups); - break; - } - case OP_GETGLOBAL: - case OP_SETGLOBAL: { - check(ttisstring(&pt->k[b])); - break; - } - case OP_SELF: { - checkreg(pt, a+1); - if (reg == a+1) last = pc; - break; - } - case OP_CONCAT: { - /* `c' is a register, and at least two operands */ - check(c < MAXSTACK && b < c); - break; - } - case OP_TFORLOOP: - checkreg(pt, a+c+5); - if (reg >= a) last = pc; /* affect all registers above base */ - /* go through */ - case OP_FORLOOP: - checkreg(pt, a+2); - /* go through */ - case OP_JMP: { - int dest = pc+1+b; - check(0 <= dest && dest < pt->sizecode); - /* not full check and jump is forward and do not skip `lastpc'? */ - if (reg != NO_REG && pc < dest && dest <= lastpc) - pc += b; /* do the jump */ - break; - } - case OP_CALL: - case OP_TAILCALL: { - if (b != 0) { - checkreg(pt, a+b-1); - } - c--; /* c = num. returns */ - if (c == LUA_MULTRET) { - check(checkopenop(pt, pc)); - } - else if (c != 0) - checkreg(pt, a+c-1); - if (reg >= a) last = pc; /* affect all registers above base */ - break; - } - case OP_RETURN: { - b--; /* b = num. returns */ - if (b > 0) checkreg(pt, a+b-1); - break; - } - case OP_SETLIST: { - checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); - break; - } - case OP_CLOSURE: { - int nup; - check(b < pt->sizep); - nup = pt->p[b]->nups; - check(pc + nup < pt->sizecode); - for (; nup>0; nup--) { - OpCode op1 = GET_OPCODE(pt->code[pc+nup]); - check(op1 == OP_GETUPVAL || op1 == OP_MOVE); - } - break; - } - default: break; - } - } - return pt->code[last]; -} - -#undef check -#undef checkjump -#undef checkreg - -/* }====================================================== */ - - -int luaG_checkcode (const Proto *pt) { - return luaG_symbexec(pt, pt->sizecode, NO_REG); -} - - -static const char *kname (Proto *p, int c) { - c = c - MAXSTACK; - if (c >= 0 && ttisstring(&p->k[c])) - return svalue(&p->k[c]); - else - return "?"; -} - - -static const char *getobjname (CallInfo *ci, int stackpos, const char **name) { - if (isLua(ci)) { /* a Lua function? */ - Proto *p = ci_func(ci)->l.p; - int pc = currentpc(ci); - Instruction i; - *name = luaF_getlocalname(p, stackpos+1, pc); - if (*name) /* is a local? */ - return "local"; - i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */ - lua_assert(pc != -1); - switch (GET_OPCODE(i)) { - case OP_GETGLOBAL: { - int g = GETARG_Bx(i); /* global index */ - lua_assert(ttisstring(&p->k[g])); - *name = svalue(&p->k[g]); - return "global"; - } - case OP_MOVE: { - int a = GETARG_A(i); - int b = GETARG_B(i); /* move from `b' to `a' */ - if (b < a) - return getobjname(ci, b, name); /* get name for `b' */ - break; - } - case OP_GETTABLE: { - int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - return "field"; - } - case OP_SELF: { - int k = GETARG_C(i); /* key index */ - *name = kname(p, k); - return "method"; - } - default: break; - } - } - return NULL; /* no useful name found */ -} - - -static const char *getfuncname (CallInfo *ci, const char **name) { - Instruction i; - if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci - 1)) - return NULL; /* calling function is not Lua (or is unknown) */ - ci--; /* calling function */ - i = ci_func(ci)->l.p->code[currentpc(ci)]; - if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL) - return getobjname(ci, GETARG_A(i), name); - else - return NULL; /* no useful name can be found */ -} - - -/* only ANSI way to check whether a pointer points to an array */ -static int isinstack (CallInfo *ci, const TObject *o) { - StkId p; - for (p = ci->base; p < ci->top; p++) - if (o == p) return 1; - return 0; -} - - -void luaG_typeerror (lua_State *L, const TObject *o, const char *op) { - const char *name = NULL; - const char *t = luaT_typenames[ttype(o)]; - const char *kind = (isinstack(L->ci, o)) ? - getobjname(L->ci, o - L->base, &name) : NULL; - if (kind) - luaG_runerror(L, "attempt to %s %s `%s' (a %s value)", - op, kind, name, t); - else - luaG_runerror(L, "attempt to %s a %s value", op, t); -} - - -void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { - if (ttisstring(p1)) p1 = p2; - lua_assert(!ttisstring(p1)); - luaG_typeerror(L, p1, "concatenate"); -} - - -void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2) { - TObject temp; - if (luaV_tonumber(p1, &temp) == NULL) - p2 = p1; /* first operand is wrong */ - luaG_typeerror(L, p2, "perform arithmetic on"); -} - - -int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) { - const char *t1 = luaT_typenames[ttype(p1)]; - const char *t2 = luaT_typenames[ttype(p2)]; - if (t1[2] == t2[2]) - luaG_runerror(L, "attempt to compare two %s values", t1); - else - luaG_runerror(L, "attempt to compare %s with %s", t1, t2); - return 0; -} - - -static void addinfo (lua_State *L, const char *msg) { - CallInfo *ci = L->ci; - if (isLua(ci)) { /* is Lua code? */ - char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(ci); - luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); - luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); - } -} - - -void luaG_errormsg (lua_State *L) { - if (L->errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L->errfunc); - if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); - setobjs2s(L->top, L->top - 1); /* move argument */ - setobjs2s(L->top - 1, errfunc); /* push function */ - incr_top(L); - luaD_call(L, L->top - 2, 1); /* call it */ - } - luaD_throw(L, LUA_ERRRUN); -} - - -void luaG_runerror (lua_State *L, const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - addinfo(L, luaO_pushvfstring(L, fmt, argp)); - va_end(argp); - luaG_errormsg(L); -} - +/*
+** $Id: ldebug.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Debug Interface
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#define ldebug_c
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+
+static const char *getfuncname (CallInfo *ci, const char **name);
+
+
+#define isLua(ci) (!((ci)->state & CI_C))
+
+
+static int currentpc (CallInfo *ci) {
+ if (!isLua(ci)) return -1; /* function is not a Lua function? */
+ if (ci->state & CI_HASFRAME) /* function has a frame? */
+ ci->u.l.savedpc = *ci->u.l.pc; /* use `pc' from there */
+ /* function's pc is saved */
+ return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p);
+}
+
+
+static int currentline (CallInfo *ci) {
+ int pc = currentpc(ci);
+ if (pc < 0)
+ return -1; /* only active lua functions have current-line information */
+ else
+ return getline(ci_func(ci)->l.p, pc);
+}
+
+
+void luaG_inithooks (lua_State *L) {
+ CallInfo *ci;
+ for (ci = L->ci; ci != L->base_ci; ci--) /* update all `savedpc's */
+ currentpc(ci);
+ L->hookinit = 1;
+}
+
+
+/*
+** this function can be called asynchronous (e.g. during a signal)
+*/
+LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
+ if (func == NULL || mask == 0) { /* turn off hooks? */
+ mask = 0;
+ func = NULL;
+ }
+ L->hook = func;
+ L->basehookcount = count;
+ resethookcount(L);
+ L->hookmask = cast(lu_byte, mask);
+ L->hookinit = 0;
+ return 1;
+}
+
+
+LUA_API lua_Hook lua_gethook (lua_State *L) {
+ return L->hook;
+}
+
+
+LUA_API int lua_gethookmask (lua_State *L) {
+ return L->hookmask;
+}
+
+
+LUA_API int lua_gethookcount (lua_State *L) {
+ return L->basehookcount;
+}
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
+ int status;
+ CallInfo *ci;
+ lua_lock(L);
+ for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) {
+ level--;
+ if (!(ci->state & CI_C)) /* Lua function? */
+ level -= ci->u.l.tailcalls; /* skip lost tail calls */
+ }
+ if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */
+ else if (level < 0) { /* level is of a lost tail call */
+ status = 1;
+ ar->i_ci = 0;
+ }
+ else {
+ status = 1;
+ ar->i_ci = ci - L->base_ci;
+ }
+ lua_unlock(L);
+ return status;
+}
+
+
+static Proto *getluaproto (CallInfo *ci) {
+ return (isLua(ci) ? ci_func(ci)->l.p : NULL);
+}
+
+
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
+ const char *name;
+ CallInfo *ci;
+ Proto *fp;
+ lua_lock(L);
+ name = NULL;
+ ci = L->base_ci + ar->i_ci;
+ fp = getluaproto(ci);
+ if (fp) { /* is a Lua function? */
+ name = luaF_getlocalname(fp, n, currentpc(ci));
+ if (name)
+ luaA_pushobject(L, ci->base+(n-1)); /* push value */
+ }
+ lua_unlock(L);
+ return name;
+}
+
+
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
+ const char *name;
+ CallInfo *ci;
+ Proto *fp;
+ lua_lock(L);
+ name = NULL;
+ ci = L->base_ci + ar->i_ci;
+ fp = getluaproto(ci);
+ L->top--; /* pop new value */
+ if (fp) { /* is a Lua function? */
+ name = luaF_getlocalname(fp, n, currentpc(ci));
+ if (!name || name[0] == '(') /* `(' starts private locals */
+ name = NULL;
+ else
+ setobjs2s(ci->base+(n-1), L->top);
+ }
+ lua_unlock(L);
+ return name;
+}
+
+
+static void funcinfo (lua_Debug *ar, StkId func) {
+ Closure *cl = clvalue(func);
+ if (cl->c.isC) {
+ ar->source = "=[C]";
+ ar->linedefined = -1;
+ ar->what = "C";
+ }
+ else {
+ ar->source = getstr(cl->l.p->source);
+ ar->linedefined = cl->l.p->lineDefined;
+ ar->what = (ar->linedefined == 0) ? "main" : "Lua";
+ }
+ luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
+}
+
+
+static const char *travglobals (lua_State *L, const TObject *o) {
+ Table *g = hvalue(gt(L));
+ int i = sizenode(g);
+ while (i--) {
+ Node *n = gnode(g, i);
+ if (luaO_rawequalObj(o, gval(n)) && ttisstring(gkey(n)))
+ return getstr(tsvalue(gkey(n)));
+ }
+ return NULL;
+}
+
+
+static void info_tailcall (lua_State *L, lua_Debug *ar) {
+ ar->name = ar->namewhat = "";
+ ar->what = "tail";
+ ar->linedefined = ar->currentline = -1;
+ ar->source = "=(tail call)";
+ luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
+ ar->nups = 0;
+ setnilvalue(L->top);
+}
+
+
+static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
+ StkId f, CallInfo *ci) {
+ int status = 1;
+ for (; *what; what++) {
+ switch (*what) {
+ case 'S': {
+ funcinfo(ar, f);
+ break;
+ }
+ case 'l': {
+ ar->currentline = (ci) ? currentline(ci) : -1;
+ break;
+ }
+ case 'u': {
+ ar->nups = clvalue(f)->c.nupvalues;
+ break;
+ }
+ case 'n': {
+ ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL;
+ if (ar->namewhat == NULL) {
+ /* try to find a global name */
+ if ((ar->name = travglobals(L, f)) != NULL)
+ ar->namewhat = "global";
+ else ar->namewhat = ""; /* not found */
+ }
+ break;
+ }
+ case 'f': {
+ setobj2s(L->top, f);
+ break;
+ }
+ default: status = 0; /* invalid option */
+ }
+ }
+ return status;
+}
+
+
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
+ int status = 1;
+ lua_lock(L);
+ if (*what == '>') {
+ StkId f = L->top - 1;
+ if (!ttisfunction(f))
+ luaG_runerror(L, "value for `lua_getinfo' is not a function");
+ status = auxgetinfo(L, what + 1, ar, f, NULL);
+ L->top--; /* pop function */
+ }
+ else if (ar->i_ci != 0) { /* no tail call? */
+ CallInfo *ci = L->base_ci + ar->i_ci;
+ lua_assert(ttisfunction(ci->base - 1));
+ status = auxgetinfo(L, what, ar, ci->base - 1, ci);
+ }
+ else
+ info_tailcall(L, ar);
+ if (strchr(what, 'f')) incr_top(L);
+ lua_unlock(L);
+ return status;
+}
+
+
+/*
+** {======================================================
+** Symbolic Execution and code checker
+** =======================================================
+*/
+
+#define check(x) if (!(x)) return 0;
+
+#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode)
+
+#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize)
+
+
+
+static int precheck (const Proto *pt) {
+ check(pt->maxstacksize <= MAXSTACK);
+ check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
+ lua_assert(pt->numparams+pt->is_vararg <= pt->maxstacksize);
+ check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
+ return 1;
+}
+
+
+static int checkopenop (const Proto *pt, int pc) {
+ Instruction i = pt->code[pc+1];
+ switch (GET_OPCODE(i)) {
+ case OP_CALL:
+ case OP_TAILCALL:
+ case OP_RETURN: {
+ check(GETARG_B(i) == 0);
+ return 1;
+ }
+ case OP_SETLISTO: return 1;
+ default: return 0; /* invalid instruction after an open call */
+ }
+}
+
+
+static int checkRK (const Proto *pt, int r) {
+ return (r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek));
+}
+
+
+static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
+ int pc;
+ int last; /* stores position of last instruction that changed `reg' */
+ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */
+ check(precheck(pt));
+ for (pc = 0; pc < lastpc; pc++) {
+ const Instruction i = pt->code[pc];
+ OpCode op = GET_OPCODE(i);
+ int a = GETARG_A(i);
+ int b = 0;
+ int c = 0;
+ checkreg(pt, a);
+ switch (getOpMode(op)) {
+ case iABC: {
+ b = GETARG_B(i);
+ c = GETARG_C(i);
+ if (testOpMode(op, OpModeBreg)) {
+ checkreg(pt, b);
+ }
+ else if (testOpMode(op, OpModeBrk))
+ check(checkRK(pt, b));
+ if (testOpMode(op, OpModeCrk))
+ check(checkRK(pt, c));
+ break;
+ }
+ case iABx: {
+ b = GETARG_Bx(i);
+ if (testOpMode(op, OpModeK)) check(b < pt->sizek);
+ break;
+ }
+ case iAsBx: {
+ b = GETARG_sBx(i);
+ break;
+ }
+ }
+ if (testOpMode(op, OpModesetA)) {
+ if (a == reg) last = pc; /* change register `a' */
+ }
+ if (testOpMode(op, OpModeT)) {
+ check(pc+2 < pt->sizecode); /* check skip */
+ check(GET_OPCODE(pt->code[pc+1]) == OP_JMP);
+ }
+ switch (op) {
+ case OP_LOADBOOL: {
+ check(c == 0 || pc+2 < pt->sizecode); /* check its jump */
+ break;
+ }
+ case OP_LOADNIL: {
+ if (a <= reg && reg <= b)
+ last = pc; /* set registers from `a' to `b' */
+ break;
+ }
+ case OP_GETUPVAL:
+ case OP_SETUPVAL: {
+ check(b < pt->nups);
+ break;
+ }
+ case OP_GETGLOBAL:
+ case OP_SETGLOBAL: {
+ check(ttisstring(&pt->k[b]));
+ break;
+ }
+ case OP_SELF: {
+ checkreg(pt, a+1);
+ if (reg == a+1) last = pc;
+ break;
+ }
+ case OP_CONCAT: {
+ /* `c' is a register, and at least two operands */
+ check(c < MAXSTACK && b < c);
+ break;
+ }
+ case OP_TFORLOOP:
+ checkreg(pt, a+c+5);
+ if (reg >= a) last = pc; /* affect all registers above base */
+ /* go through */
+ case OP_FORLOOP:
+ checkreg(pt, a+2);
+ /* go through */
+ case OP_JMP: {
+ int dest = pc+1+b;
+ check(0 <= dest && dest < pt->sizecode);
+ /* not full check and jump is forward and do not skip `lastpc'? */
+ if (reg != NO_REG && pc < dest && dest <= lastpc)
+ pc += b; /* do the jump */
+ break;
+ }
+ case OP_CALL:
+ case OP_TAILCALL: {
+ if (b != 0) {
+ checkreg(pt, a+b-1);
+ }
+ c--; /* c = num. returns */
+ if (c == LUA_MULTRET) {
+ check(checkopenop(pt, pc));
+ }
+ else if (c != 0)
+ checkreg(pt, a+c-1);
+ if (reg >= a) last = pc; /* affect all registers above base */
+ break;
+ }
+ case OP_RETURN: {
+ b--; /* b = num. returns */
+ if (b > 0) checkreg(pt, a+b-1);
+ break;
+ }
+ case OP_SETLIST: {
+ checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1);
+ break;
+ }
+ case OP_CLOSURE: {
+ int nup;
+ check(b < pt->sizep);
+ nup = pt->p[b]->nups;
+ check(pc + nup < pt->sizecode);
+ for (; nup>0; nup--) {
+ OpCode op1 = GET_OPCODE(pt->code[pc+nup]);
+ check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
+ }
+ break;
+ }
+ default: break;
+ }
+ }
+ return pt->code[last];
+}
+
+#undef check
+#undef checkjump
+#undef checkreg
+
+/* }====================================================== */
+
+
+int luaG_checkcode (const Proto *pt) {
+ return luaG_symbexec(pt, pt->sizecode, NO_REG);
+}
+
+
+static const char *kname (Proto *p, int c) {
+ c = c - MAXSTACK;
+ if (c >= 0 && ttisstring(&p->k[c]))
+ return svalue(&p->k[c]);
+ else
+ return "?";
+}
+
+
+static const char *getobjname (CallInfo *ci, int stackpos, const char **name) {
+ if (isLua(ci)) { /* a Lua function? */
+ Proto *p = ci_func(ci)->l.p;
+ int pc = currentpc(ci);
+ Instruction i;
+ *name = luaF_getlocalname(p, stackpos+1, pc);
+ if (*name) /* is a local? */
+ return "local";
+ i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */
+ lua_assert(pc != -1);
+ switch (GET_OPCODE(i)) {
+ case OP_GETGLOBAL: {
+ int g = GETARG_Bx(i); /* global index */
+ lua_assert(ttisstring(&p->k[g]));
+ *name = svalue(&p->k[g]);
+ return "global";
+ }
+ case OP_MOVE: {
+ int a = GETARG_A(i);
+ int b = GETARG_B(i); /* move from `b' to `a' */
+ if (b < a)
+ return getobjname(ci, b, name); /* get name for `b' */
+ break;
+ }
+ case OP_GETTABLE: {
+ int k = GETARG_C(i); /* key index */
+ *name = kname(p, k);
+ return "field";
+ }
+ case OP_SELF: {
+ int k = GETARG_C(i); /* key index */
+ *name = kname(p, k);
+ return "method";
+ }
+ default: break;
+ }
+ }
+ return NULL; /* no useful name found */
+}
+
+
+static const char *getfuncname (CallInfo *ci, const char **name) {
+ Instruction i;
+ if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci - 1))
+ return NULL; /* calling function is not Lua (or is unknown) */
+ ci--; /* calling function */
+ i = ci_func(ci)->l.p->code[currentpc(ci)];
+ if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL)
+ return getobjname(ci, GETARG_A(i), name);
+ else
+ return NULL; /* no useful name can be found */
+}
+
+
+/* only ANSI way to check whether a pointer points to an array */
+static int isinstack (CallInfo *ci, const TObject *o) {
+ StkId p;
+ for (p = ci->base; p < ci->top; p++)
+ if (o == p) return 1;
+ return 0;
+}
+
+
+void luaG_typeerror (lua_State *L, const TObject *o, const char *op) {
+ const char *name = NULL;
+ const char *t = luaT_typenames[ttype(o)];
+ const char *kind = (isinstack(L->ci, o)) ?
+ getobjname(L->ci, o - L->base, &name) : NULL;
+ if (kind)
+ luaG_runerror(L, "attempt to %s %s `%s' (a %s value)",
+ op, kind, name, t);
+ else
+ luaG_runerror(L, "attempt to %s a %s value", op, t);
+}
+
+
+void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
+ if (ttisstring(p1)) p1 = p2;
+ lua_assert(!ttisstring(p1));
+ luaG_typeerror(L, p1, "concatenate");
+}
+
+
+void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2) {
+ TObject temp;
+ if (luaV_tonumber(p1, &temp) == NULL)
+ p2 = p1; /* first operand is wrong */
+ luaG_typeerror(L, p2, "perform arithmetic on");
+}
+
+
+int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) {
+ const char *t1 = luaT_typenames[ttype(p1)];
+ const char *t2 = luaT_typenames[ttype(p2)];
+ if (t1[2] == t2[2])
+ luaG_runerror(L, "attempt to compare two %s values", t1);
+ else
+ luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
+ return 0;
+}
+
+
+static void addinfo (lua_State *L, const char *msg) {
+ CallInfo *ci = L->ci;
+ if (isLua(ci)) { /* is Lua code? */
+ char buff[LUA_IDSIZE]; /* add file:line information */
+ int line = currentline(ci);
+ luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE);
+ luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
+ }
+}
+
+
+void luaG_errormsg (lua_State *L) {
+ if (L->errfunc != 0) { /* is there an error handling function? */
+ StkId errfunc = restorestack(L, L->errfunc);
+ if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
+ setobjs2s(L->top, L->top - 1); /* move argument */
+ setobjs2s(L->top - 1, errfunc); /* push function */
+ incr_top(L);
+ luaD_call(L, L->top - 2, 1); /* call it */
+ }
+ luaD_throw(L, LUA_ERRRUN);
+}
+
+
+void luaG_runerror (lua_State *L, const char *fmt, ...) {
+ va_list argp;
+ va_start(argp, fmt);
+ addinfo(L, luaO_pushvfstring(L, fmt, argp));
+ va_end(argp);
+ luaG_errormsg(L);
+}
+
diff --git a/lib/lua/src/ldo.c b/lib/lua/src/ldo.c index 44bba83..8c64852 100644 --- a/lib/lua/src/ldo.c +++ b/lib/lua/src/ldo.c @@ -1,465 +1,465 @@ -/* -** $Id: ldo.c,v 1.3 2004-07-23 13:08:23 pixel Exp $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - - -#include <setjmp.h> -#include <stdlib.h> -#include <string.h> - -#define ldo_c - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lundump.h" -#include "lvm.h" -#include "lzio.h" - - - - -/* -** {====================================================== -** Error-recovery functions (based on long jumps) -** ======================================================= -*/ - - -/* chain list of long jump buffers */ -struct lua_longjmp { - struct lua_longjmp *previous; - jmp_buf b; - volatile int status; /* error code */ -}; - - -static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { - switch (errcode) { - case LUA_ERRMEM: { - setsvalue2s(oldtop, luaS_new(L, MEMERRMSG)); - break; - } - case LUA_ERRERR: { - setsvalue2s(oldtop, luaS_new(L, "error in error handling")); - break; - } - case LUA_ERRSYNTAX: - case LUA_ERRRUN: { - setobjs2s(oldtop, L->top - 1); /* error message on current top */ - break; - } - } - L->top = oldtop + 1; -} - - -void luaD_throw (lua_State *L, int errcode) { - if (L->errorJmp) { - L->errorJmp->status = errcode; - longjmp(L->errorJmp->b, 1); - } - else { - G(L)->panic(L); - exit(EXIT_FAILURE); - } -} - - -int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { - struct lua_longjmp lj; - lj.status = 0; - lj.previous = L->errorJmp; /* chain new error handler */ - L->errorJmp = &lj; - if (setjmp(lj.b) == 0) - (*f)(L, ud); - L->errorJmp = lj.previous; /* restore old error handler */ - return lj.status; -} - - -static void restore_stack_limit (lua_State *L) { - L->stack_last = L->stack+L->stacksize-1; - if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */ - int inuse = (L->ci - L->base_ci); - if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUA_MAXCALLS); - } -} - -/* }====================================================== */ - - -static void correctstack (lua_State *L, TObject *oldstack) { - CallInfo *ci; - GCObject *up; - L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->gch.next) - gcotouv(up)->v = (gcotouv(up)->v - oldstack) + L->stack; - for (ci = L->base_ci; ci <= L->ci; ci++) { - ci->top = (ci->top - oldstack) + L->stack; - ci->base = (ci->base - oldstack) + L->stack; - } - L->base = L->ci->base; -} - - -void luaD_reallocstack (lua_State *L, int newsize) { - TObject *oldstack = L->stack; - luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject); - L->stacksize = newsize; - L->stack_last = L->stack+newsize-1-EXTRA_STACK; - correctstack(L, oldstack); -} - - -void luaD_reallocCI (lua_State *L, int newsize) { - CallInfo *oldci = L->base_ci; - luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); - L->size_ci = cast(unsigned short, newsize); - L->ci = (L->ci - oldci) + L->base_ci; - L->end_ci = L->base_ci + L->size_ci; -} - - -void luaD_growstack (lua_State *L, int n) { - if (n <= L->stacksize) /* double size is enough? */ - luaD_reallocstack(L, 2*L->stacksize); - else - luaD_reallocstack(L, L->stacksize + n + EXTRA_STACK); -} - - -static void luaD_growCI (lua_State *L) { - if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */ - luaD_throw(L, LUA_ERRERR); - else { - luaD_reallocCI(L, 2*L->size_ci); - if (L->size_ci > LUA_MAXCALLS) - luaG_runerror(L, "stack overflow"); - } -} - - -void luaD_callhook (lua_State *L, int event, int line) { - lua_Hook hook = L->hook; - if (hook && L->allowhook) { - ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, L->ci->top); - lua_Debug ar; - ar.event = event; - ar.currentline = line; - if (event == LUA_HOOKTAILRET) - ar.i_ci = 0; /* tail call; no debug information about it */ - else - ar.i_ci = L->ci - L->base_ci; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - L->ci->top = L->top + LUA_MINSTACK; - L->allowhook = 0; /* cannot call hooks inside a hook */ - lua_unlock(L); - (*hook)(L, &ar); - lua_lock(L); - lua_assert(!L->allowhook); - L->allowhook = 1; - L->ci->top = restorestack(L, ci_top); - L->top = restorestack(L, top); - } -} - - -static void adjust_varargs (lua_State *L, int nfixargs, StkId base) { - int i; - Table *htab; - TObject nname; - int actual = L->top - base; /* actual number of arguments */ - if (actual < nfixargs) { - luaD_checkstack(L, nfixargs - actual); - for (; actual < nfixargs; ++actual) - setnilvalue(L->top++); - } - actual -= nfixargs; /* number of extra arguments */ - htab = luaH_new(L, actual, 1); /* create `arg' table */ - for (i=0; i<actual; i++) /* put extra arguments into `arg' table */ - setobj2n(luaH_setnum(L, htab, i+1), L->top - actual + i); - /* store counter in field `n' */ - setsvalue(&nname, luaS_newliteral(L, "n")); - setnvalue(luaH_set(L, htab, &nname), cast(lua_Number, actual)); - L->top -= actual; /* remove extra elements from the stack */ - sethvalue(L->top, htab); - incr_top(L); -} - - -static StkId tryfuncTM (lua_State *L, StkId func) { - const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); - StkId p; - ptrdiff_t funcr = savestack(L, func); - if (!ttisfunction(tm)) - luaG_typeerror(L, func, "call"); - /* Open a hole inside the stack at `func' */ - for (p = L->top; p > func; p--) setobjs2s(p, p-1); - incr_top(L); - func = restorestack(L, funcr); /* previous call may change stack */ - setobj2s(func, tm); /* tag method is the new function to be called */ - return func; -} - - -StkId luaD_precall (lua_State *L, StkId func) { - LClosure *cl; - ptrdiff_t funcr = savestack(L, func); - if (!ttisfunction(func)) /* `func' is not a function? */ - func = tryfuncTM(L, func); /* check the `function' tag method */ - if (L->ci + 1 == L->end_ci) luaD_growCI(L); - else condhardstacktests(luaD_reallocCI(L, L->size_ci)); - cl = &clvalue(func)->l; - if (!cl->isC) { /* Lua function? prepare its call */ - CallInfo *ci; - Proto *p = cl->p; - if (p->is_vararg) /* varargs? */ - adjust_varargs(L, p->numparams, func+1); - luaD_checkstack(L, p->maxstacksize); - ci = ++L->ci; /* now `enter' new function */ - L->base = L->ci->base = restorestack(L, funcr) + 1; - ci->top = L->base + p->maxstacksize; - ci->u.l.savedpc = p->code; /* starting point */ - ci->u.l.tailcalls = 0; - ci->state = CI_SAVEDPC; - while (L->top < ci->top) - setnilvalue(L->top++); - L->top = ci->top; - return NULL; - } - else { /* if is a C function, call it */ - CallInfo *ci; - int n; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = ++L->ci; /* now `enter' new function */ - L->base = L->ci->base = restorestack(L, funcr) + 1; - ci->top = L->top + LUA_MINSTACK; - ci->state = CI_C; /* a C function */ - if (L->hookmask & LUA_MASKCALL) - luaD_callhook(L, LUA_HOOKCALL, -1); - lua_unlock(L); -#ifdef LUA_COMPATUPVALUES - lua_pushupvalues(L); -#endif - n = (*clvalue(L->base - 1)->c.f)(L); /* do the actual call */ - lua_lock(L); - return L->top - n; - } -} - - -static StkId callrethooks (lua_State *L, StkId firstResult) { - ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ - luaD_callhook(L, LUA_HOOKRET, -1); - if (!(L->ci->state & CI_C)) { /* Lua function? */ - while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */ - luaD_callhook(L, LUA_HOOKTAILRET, -1); - } - return restorestack(L, fr); -} - - -void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { - StkId res; - if (L->hookmask & LUA_MASKRET) - firstResult = callrethooks(L, firstResult); - res = L->base - 1; /* res == final position of 1st result */ - L->ci--; - L->base = L->ci->base; /* restore base */ - /* move results to correct place */ - while (wanted != 0 && firstResult < L->top) { - setobjs2s(res++, firstResult++); - wanted--; - } - while (wanted-- > 0) - setnilvalue(res++); - L->top = res; -} - - -/* -** Call a function (C or Lua). The function to be called is at *func. -** The arguments are on the stack, right after the function. -** When returns, all the results are on the stack, starting at the original -** function position. -*/ -void luaD_call (lua_State *L, StkId func, int nResults) { - StkId firstResult; - lua_assert(!(L->ci->state & CI_CALLING)); - if (++L->nCcalls >= LUA_MAXCCALLS) { - if (L->nCcalls == LUA_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3))) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ - } - firstResult = luaD_precall(L, func); - if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L); /* call it */ - luaD_poscall(L, nResults, firstResult); - L->nCcalls--; - luaC_checkGC(L); -} - - -static void resume (lua_State *L, void *ud) { - StkId firstResult; - int nargs = *cast(int *, ud); - CallInfo *ci = L->ci; - if (ci == L->base_ci) { /* no activation record? */ - if (nargs >= L->top - L->base) - luaG_runerror(L, "cannot resume dead coroutine"); - luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ - } - else if (ci->state & CI_YIELD) { /* inside a yield? */ - if (ci->state & CI_C) { /* `common' yield? */ - /* finish interrupted execution of `OP_CALL' */ - int nresults; - lua_assert((ci-1)->state & CI_SAVEDPC); - lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); - nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; - luaD_poscall(L, nresults, L->top - nargs); /* complete it */ - if (nresults >= 0) L->top = L->ci->top; - } - else { /* yielded inside a hook: just continue its execution */ - ci->state &= ~CI_YIELD; - } - } - else - luaG_runerror(L, "cannot resume non-suspended coroutine"); - firstResult = luaV_execute(L); - if (firstResult != NULL) /* return? */ - luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ -} - - -LUA_API int lua_resume (lua_State *L, int nargs) { - int status; - lu_byte old_allowhooks; - lua_lock(L); - old_allowhooks = L->allowhook; - lua_assert(L->errfunc == 0 && L->nCcalls == 0); - status = luaD_rawrunprotected(L, resume, &nargs); - if (status != 0) { /* error? */ - L->ci = L->base_ci; /* go back to initial level */ - L->base = L->ci->base; - L->nCcalls = 0; - luaF_close(L, L->base); /* close eventual pending closures */ - seterrorobj(L, status, L->base); - L->allowhook = old_allowhooks; - restore_stack_limit(L); - } - lua_unlock(L); - return status; -} - - -LUA_API int lua_yield (lua_State *L, int nresults) { - CallInfo *ci; - lua_lock(L); - ci = L->ci; - if (L->nCcalls > 0) - luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - if (ci->state & CI_C) { /* usual yield */ - if ((ci-1)->state & CI_C) - luaG_runerror(L, "cannot yield a C function"); - if (L->top - nresults > L->base) { /* is there garbage in the stack? */ - int i; - for (i=0; i<nresults; i++) /* move down results */ - setobjs2s(L->base + i, L->top - nresults + i); - L->top = L->base + nresults; - } - } /* else it's an yield inside a hook: nothing to do */ - ci->state |= CI_YIELD; - lua_unlock(L); - return -1; -} - -LUA_API void lua_break (lua_State *L) { - CallInfo * ci; - lua_lock(L); - ci = L->ci; - ci->state |= CI_BREAK; - lua_unlock(L); -} - -int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t old_top, ptrdiff_t ef) { - int status; - unsigned short oldnCcalls = L->nCcalls; - ptrdiff_t old_ci = saveci(L, L->ci); - lu_byte old_allowhooks = L->allowhook; - ptrdiff_t old_errfunc = L->errfunc; - L->errfunc = ef; - status = luaD_rawrunprotected(L, func, u); - if (status != 0) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close eventual pending closures */ - seterrorobj(L, status, oldtop); - L->nCcalls = oldnCcalls; - L->ci = restoreci(L, old_ci); - L->base = L->ci->base; - L->allowhook = old_allowhooks; - restore_stack_limit(L); - } - L->errfunc = old_errfunc; - return status; -} - - - -/* -** Execute a protected parser. -*/ -struct SParser { /* data to `f_parser' */ - ZIO *z; - Mbuffer buff; /* buffer to be used by the scanner */ - int bin; -}; - -static void f_parser (lua_State *L, void *ud) { - struct SParser *p; - Proto *tf; - Closure *cl; - luaC_checkGC(L); - p = cast(struct SParser *, ud); - tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff); - cl = luaF_newLclosure(L, 0, gt(L)); - cl->l.p = tf; - setclvalue(L->top, cl); - incr_top(L); -} - - -int luaD_protectedparser (lua_State *L, ZIO *z, int bin) { - struct SParser p; - int status; - ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */ - p.z = z; p.bin = bin; - luaZ_initbuffer(L, &p.buff); - status = luaD_rawrunprotected(L, f_parser, &p); - luaZ_freebuffer(L, &p.buff); - if (status != 0) { /* error? */ - StkId oldtop = restorestack(L, oldtopr); - seterrorobj(L, status, oldtop); - } - return status; -} - - +/*
+** $Id: ldo.c,v 1.4 2004-11-27 21:35:20 pixel Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ldo_c
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+#include "lzio.h"
+
+
+
+
+/*
+** {======================================================
+** Error-recovery functions (based on long jumps)
+** =======================================================
+*/
+
+
+/* chain list of long jump buffers */
+struct lua_longjmp {
+ struct lua_longjmp *previous;
+ jmp_buf b;
+ volatile int status; /* error code */
+};
+
+
+static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
+ switch (errcode) {
+ case LUA_ERRMEM: {
+ setsvalue2s(oldtop, luaS_new(L, MEMERRMSG));
+ break;
+ }
+ case LUA_ERRERR: {
+ setsvalue2s(oldtop, luaS_new(L, "error in error handling"));
+ break;
+ }
+ case LUA_ERRSYNTAX:
+ case LUA_ERRRUN: {
+ setobjs2s(oldtop, L->top - 1); /* error message on current top */
+ break;
+ }
+ }
+ L->top = oldtop + 1;
+}
+
+
+void luaD_throw (lua_State *L, int errcode) {
+ if (L->errorJmp) {
+ L->errorJmp->status = errcode;
+ longjmp(L->errorJmp->b, 1);
+ }
+ else {
+ G(L)->panic(L);
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
+ struct lua_longjmp lj;
+ lj.status = 0;
+ lj.previous = L->errorJmp; /* chain new error handler */
+ L->errorJmp = &lj;
+ if (setjmp(lj.b) == 0)
+ (*f)(L, ud);
+ L->errorJmp = lj.previous; /* restore old error handler */
+ return lj.status;
+}
+
+
+static void restore_stack_limit (lua_State *L) {
+ L->stack_last = L->stack+L->stacksize-1;
+ if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */
+ int inuse = (L->ci - L->base_ci);
+ if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */
+ luaD_reallocCI(L, LUA_MAXCALLS);
+ }
+}
+
+/* }====================================================== */
+
+
+static void correctstack (lua_State *L, TObject *oldstack) {
+ CallInfo *ci;
+ GCObject *up;
+ L->top = (L->top - oldstack) + L->stack;
+ for (up = L->openupval; up != NULL; up = up->gch.next)
+ gcotouv(up)->v = (gcotouv(up)->v - oldstack) + L->stack;
+ for (ci = L->base_ci; ci <= L->ci; ci++) {
+ ci->top = (ci->top - oldstack) + L->stack;
+ ci->base = (ci->base - oldstack) + L->stack;
+ }
+ L->base = L->ci->base;
+}
+
+
+void luaD_reallocstack (lua_State *L, int newsize) {
+ TObject *oldstack = L->stack;
+ luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject);
+ L->stacksize = newsize;
+ L->stack_last = L->stack+newsize-1-EXTRA_STACK;
+ correctstack(L, oldstack);
+}
+
+
+void luaD_reallocCI (lua_State *L, int newsize) {
+ CallInfo *oldci = L->base_ci;
+ luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo);
+ L->size_ci = cast(unsigned short, newsize);
+ L->ci = (L->ci - oldci) + L->base_ci;
+ L->end_ci = L->base_ci + L->size_ci;
+}
+
+
+void luaD_growstack (lua_State *L, int n) {
+ if (n <= L->stacksize) /* double size is enough? */
+ luaD_reallocstack(L, 2*L->stacksize);
+ else
+ luaD_reallocstack(L, L->stacksize + n + EXTRA_STACK);
+}
+
+
+static void luaD_growCI (lua_State *L) {
+ if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */
+ luaD_throw(L, LUA_ERRERR);
+ else {
+ luaD_reallocCI(L, 2*L->size_ci);
+ if (L->size_ci > LUA_MAXCALLS)
+ luaG_runerror(L, "stack overflow");
+ }
+}
+
+
+void luaD_callhook (lua_State *L, int event, int line) {
+ lua_Hook hook = L->hook;
+ if (hook && L->allowhook) {
+ ptrdiff_t top = savestack(L, L->top);
+ ptrdiff_t ci_top = savestack(L, L->ci->top);
+ lua_Debug ar;
+ ar.event = event;
+ ar.currentline = line;
+ if (event == LUA_HOOKTAILRET)
+ ar.i_ci = 0; /* tail call; no debug information about it */
+ else
+ ar.i_ci = L->ci - L->base_ci;
+ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ L->ci->top = L->top + LUA_MINSTACK;
+ L->allowhook = 0; /* cannot call hooks inside a hook */
+ lua_unlock(L);
+ (*hook)(L, &ar);
+ lua_lock(L);
+ lua_assert(!L->allowhook);
+ L->allowhook = 1;
+ L->ci->top = restorestack(L, ci_top);
+ L->top = restorestack(L, top);
+ }
+}
+
+
+static void adjust_varargs (lua_State *L, int nfixargs, StkId base) {
+ int i;
+ Table *htab;
+ TObject nname;
+ int actual = L->top - base; /* actual number of arguments */
+ if (actual < nfixargs) {
+ luaD_checkstack(L, nfixargs - actual);
+ for (; actual < nfixargs; ++actual)
+ setnilvalue(L->top++);
+ }
+ actual -= nfixargs; /* number of extra arguments */
+ htab = luaH_new(L, actual, 1); /* create `arg' table */
+ for (i=0; i<actual; i++) /* put extra arguments into `arg' table */
+ setobj2n(luaH_setnum(L, htab, i+1), L->top - actual + i);
+ /* store counter in field `n' */
+ setsvalue(&nname, luaS_newliteral(L, "n"));
+ setnvalue(luaH_set(L, htab, &nname), cast(lua_Number, actual));
+ L->top -= actual; /* remove extra elements from the stack */
+ sethvalue(L->top, htab);
+ incr_top(L);
+}
+
+
+static StkId tryfuncTM (lua_State *L, StkId func) {
+ const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL);
+ StkId p;
+ ptrdiff_t funcr = savestack(L, func);
+ if (!ttisfunction(tm))
+ luaG_typeerror(L, func, "call");
+ /* Open a hole inside the stack at `func' */
+ for (p = L->top; p > func; p--) setobjs2s(p, p-1);
+ incr_top(L);
+ func = restorestack(L, funcr); /* previous call may change stack */
+ setobj2s(func, tm); /* tag method is the new function to be called */
+ return func;
+}
+
+
+StkId luaD_precall (lua_State *L, StkId func) {
+ LClosure *cl;
+ ptrdiff_t funcr = savestack(L, func);
+ if (!ttisfunction(func)) /* `func' is not a function? */
+ func = tryfuncTM(L, func); /* check the `function' tag method */
+ if (L->ci + 1 == L->end_ci) luaD_growCI(L);
+ else condhardstacktests(luaD_reallocCI(L, L->size_ci));
+ cl = &clvalue(func)->l;
+ if (!cl->isC) { /* Lua function? prepare its call */
+ CallInfo *ci;
+ Proto *p = cl->p;
+ if (p->is_vararg) /* varargs? */
+ adjust_varargs(L, p->numparams, func+1);
+ luaD_checkstack(L, p->maxstacksize);
+ ci = ++L->ci; /* now `enter' new function */
+ L->base = L->ci->base = restorestack(L, funcr) + 1;
+ ci->top = L->base + p->maxstacksize;
+ ci->u.l.savedpc = p->code; /* starting point */
+ ci->u.l.tailcalls = 0;
+ ci->state = CI_SAVEDPC;
+ while (L->top < ci->top)
+ setnilvalue(L->top++);
+ L->top = ci->top;
+ return NULL;
+ }
+ else { /* if is a C function, call it */
+ CallInfo *ci;
+ int n;
+ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ ci = ++L->ci; /* now `enter' new function */
+ L->base = L->ci->base = restorestack(L, funcr) + 1;
+ ci->top = L->top + LUA_MINSTACK;
+ ci->state = CI_C; /* a C function */
+ if (L->hookmask & LUA_MASKCALL)
+ luaD_callhook(L, LUA_HOOKCALL, -1);
+ lua_unlock(L);
+#ifdef LUA_COMPATUPVALUES
+ lua_pushupvalues(L);
+#endif
+ n = (*clvalue(L->base - 1)->c.f)(L); /* do the actual call */
+ lua_lock(L);
+ return L->top - n;
+ }
+}
+
+
+static StkId callrethooks (lua_State *L, StkId firstResult) {
+ ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */
+ luaD_callhook(L, LUA_HOOKRET, -1);
+ if (!(L->ci->state & CI_C)) { /* Lua function? */
+ while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */
+ luaD_callhook(L, LUA_HOOKTAILRET, -1);
+ }
+ return restorestack(L, fr);
+}
+
+
+void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
+ StkId res;
+ if (L->hookmask & LUA_MASKRET)
+ firstResult = callrethooks(L, firstResult);
+ res = L->base - 1; /* res == final position of 1st result */
+ L->ci--;
+ L->base = L->ci->base; /* restore base */
+ /* move results to correct place */
+ while (wanted != 0 && firstResult < L->top) {
+ setobjs2s(res++, firstResult++);
+ wanted--;
+ }
+ while (wanted-- > 0)
+ setnilvalue(res++);
+ L->top = res;
+}
+
+
+/*
+** Call a function (C or Lua). The function to be called is at *func.
+** The arguments are on the stack, right after the function.
+** When returns, all the results are on the stack, starting at the original
+** function position.
+*/
+void luaD_call (lua_State *L, StkId func, int nResults) {
+ StkId firstResult;
+ lua_assert(!(L->ci->state & CI_CALLING));
+ if (++L->nCcalls >= LUA_MAXCCALLS) {
+ if (L->nCcalls == LUA_MAXCCALLS)
+ luaG_runerror(L, "C stack overflow");
+ else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3)))
+ luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
+ }
+ firstResult = luaD_precall(L, func);
+ if (firstResult == NULL) /* is a Lua function? */
+ firstResult = luaV_execute(L); /* call it */
+ luaD_poscall(L, nResults, firstResult);
+ L->nCcalls--;
+ luaC_checkGC(L);
+}
+
+
+static void resume (lua_State *L, void *ud) {
+ StkId firstResult;
+ int nargs = *cast(int *, ud);
+ CallInfo *ci = L->ci;
+ if (ci == L->base_ci) { /* no activation record? */
+ if (nargs >= L->top - L->base)
+ luaG_runerror(L, "cannot resume dead coroutine");
+ luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */
+ }
+ else if (ci->state & CI_YIELD) { /* inside a yield? */
+ if (ci->state & CI_C) { /* `common' yield? */
+ /* finish interrupted execution of `OP_CALL' */
+ int nresults;
+ lua_assert((ci-1)->state & CI_SAVEDPC);
+ lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL ||
+ GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL);
+ nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1;
+ luaD_poscall(L, nresults, L->top - nargs); /* complete it */
+ if (nresults >= 0) L->top = L->ci->top;
+ }
+ else { /* yielded inside a hook: just continue its execution */
+ ci->state &= ~CI_YIELD;
+ }
+ }
+ else
+ luaG_runerror(L, "cannot resume non-suspended coroutine");
+ firstResult = luaV_execute(L);
+ if (firstResult != NULL) /* return? */
+ luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */
+}
+
+
+LUA_API int lua_resume (lua_State *L, int nargs) {
+ int status;
+ lu_byte old_allowhooks;
+ lua_lock(L);
+ old_allowhooks = L->allowhook;
+ lua_assert(L->errfunc == 0 && L->nCcalls == 0);
+ status = luaD_rawrunprotected(L, resume, &nargs);
+ if (status != 0) { /* error? */
+ L->ci = L->base_ci; /* go back to initial level */
+ L->base = L->ci->base;
+ L->nCcalls = 0;
+ luaF_close(L, L->base); /* close eventual pending closures */
+ seterrorobj(L, status, L->base);
+ L->allowhook = old_allowhooks;
+ restore_stack_limit(L);
+ }
+ lua_unlock(L);
+ return status;
+}
+
+
+LUA_API int lua_yield (lua_State *L, int nresults) {
+ CallInfo *ci;
+ lua_lock(L);
+ ci = L->ci;
+ if (L->nCcalls > 0)
+ luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
+ if (ci->state & CI_C) { /* usual yield */
+ if ((ci-1)->state & CI_C)
+ luaG_runerror(L, "cannot yield a C function");
+ if (L->top - nresults > L->base) { /* is there garbage in the stack? */
+ int i;
+ for (i=0; i<nresults; i++) /* move down results */
+ setobjs2s(L->base + i, L->top - nresults + i);
+ L->top = L->base + nresults;
+ }
+ } /* else it's an yield inside a hook: nothing to do */
+ ci->state |= CI_YIELD;
+ lua_unlock(L);
+ return -1;
+}
+
+LUA_API void lua_break (lua_State *L) {
+ CallInfo * ci;
+ lua_lock(L);
+ ci = L->ci;
+ ci->state |= CI_BREAK;
+ lua_unlock(L);
+}
+
+int luaD_pcall (lua_State *L, Pfunc func, void *u,
+ ptrdiff_t old_top, ptrdiff_t ef) {
+ int status;
+ unsigned short oldnCcalls = L->nCcalls;
+ ptrdiff_t old_ci = saveci(L, L->ci);
+ lu_byte old_allowhooks = L->allowhook;
+ ptrdiff_t old_errfunc = L->errfunc;
+ L->errfunc = ef;
+ status = luaD_rawrunprotected(L, func, u);
+ if (status != 0) { /* an error occurred? */
+ StkId oldtop = restorestack(L, old_top);
+ luaF_close(L, oldtop); /* close eventual pending closures */
+ seterrorobj(L, status, oldtop);
+ L->nCcalls = oldnCcalls;
+ L->ci = restoreci(L, old_ci);
+ L->base = L->ci->base;
+ L->allowhook = old_allowhooks;
+ restore_stack_limit(L);
+ }
+ L->errfunc = old_errfunc;
+ return status;
+}
+
+
+
+/*
+** Execute a protected parser.
+*/
+struct SParser { /* data to `f_parser' */
+ ZIO *z;
+ Mbuffer buff; /* buffer to be used by the scanner */
+ int bin;
+};
+
+static void f_parser (lua_State *L, void *ud) {
+ struct SParser *p;
+ Proto *tf;
+ Closure *cl;
+ luaC_checkGC(L);
+ p = cast(struct SParser *, ud);
+ tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff);
+ cl = luaF_newLclosure(L, 0, gt(L));
+ cl->l.p = tf;
+ setclvalue(L->top, cl);
+ incr_top(L);
+}
+
+
+int luaD_protectedparser (lua_State *L, ZIO *z, int bin) {
+ struct SParser p;
+ int status;
+ ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */
+ p.z = z; p.bin = bin;
+ luaZ_initbuffer(L, &p.buff);
+ status = luaD_rawrunprotected(L, f_parser, &p);
+ luaZ_freebuffer(L, &p.buff);
+ if (status != 0) { /* error? */
+ StkId oldtop = restorestack(L, oldtopr);
+ seterrorobj(L, status, oldtop);
+ }
+ return status;
+}
+
+
diff --git a/lib/lua/src/ldump.c b/lib/lua/src/ldump.c index 8af848b..47a2140 100644 --- a/lib/lua/src/ldump.c +++ b/lib/lua/src/ldump.c @@ -1,170 +1,170 @@ -/* -** $Id: ldump.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** save bytecodes -** See Copyright Notice in lua.h -*/ - -#include <stddef.h> - -#define ldump_c - -#include "lua.h" - -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lundump.h" - -#define DumpVector(b,n,size,D) DumpBlock(b,(n)*(size),D) -#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D) - -typedef struct { - lua_State* L; - lua_Chunkwriter write; - void* data; -} DumpState; - -static void DumpBlock(const void* b, size_t size, DumpState* D) -{ - lua_unlock(D->L); - (*D->write)(D->L,b,size,D->data); - lua_lock(D->L); -} - -static void DumpByte(int y, DumpState* D) -{ - char x=(char)y; - DumpBlock(&x,sizeof(x),D); -} - -static void DumpInt(int x, DumpState* D) -{ - DumpBlock(&x,sizeof(x),D); -} - -static void DumpSize(size_t x, DumpState* D) -{ - DumpBlock(&x,sizeof(x),D); -} - -static void DumpNumber(lua_Number x, DumpState* D) -{ - DumpBlock(&x,sizeof(x),D); -} - -static void DumpString(TString* s, DumpState* D) -{ - if (s==NULL || getstr(s)==NULL) - DumpSize(0,D); - else - { - size_t size=s->tsv.len+1; /* include trailing '\0' */ - DumpSize(size,D); - DumpBlock(getstr(s),size,D); - } -} - -static void DumpCode(const Proto* f, DumpState* D) -{ - DumpInt(f->sizecode,D); - DumpVector(f->code,f->sizecode,sizeof(*f->code),D); -} - -static void DumpLocals(const Proto* f, DumpState* D) -{ - int i,n=f->sizelocvars; - DumpInt(n,D); - for (i=0; i<n; i++) - { - DumpString(f->locvars[i].varname,D); - DumpInt(f->locvars[i].startpc,D); - DumpInt(f->locvars[i].endpc,D); - } -} - -static void DumpLines(const Proto* f, DumpState* D) -{ - DumpInt(f->sizelineinfo,D); - DumpVector(f->lineinfo,f->sizelineinfo,sizeof(*f->lineinfo),D); -} - -static void DumpUpvalues(const Proto* f, DumpState* D) -{ - int i,n=f->sizeupvalues; - DumpInt(n,D); - for (i=0; i<n; i++) DumpString(f->upvalues[i],D); -} - -static void DumpFunction(const Proto* f, const TString* p, DumpState* D); - -static void DumpConstants(const Proto* f, DumpState* D) -{ - int i,n; - DumpInt(n=f->sizek,D); - for (i=0; i<n; i++) - { - const TObject* o=&f->k[i]; - DumpByte(ttype(o),D); - switch (ttype(o)) - { - case LUA_TNUMBER: - DumpNumber(nvalue(o),D); - break; - case LUA_TSTRING: - DumpString(tsvalue(o),D); - break; - case LUA_TNIL: - break; - default: - lua_assert(0); /* cannot happen */ - break; - } - } - DumpInt(n=f->sizep,D); - for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D); -} - -static void DumpFunction(const Proto* f, const TString* p, DumpState* D) -{ - DumpString((f->source==p) ? NULL : f->source,D); - DumpInt(f->lineDefined,D); - DumpByte(f->nups,D); - DumpByte(f->numparams,D); - DumpByte(f->is_vararg,D); - DumpByte(f->maxstacksize,D); - DumpLines(f,D); - DumpLocals(f,D); - DumpUpvalues(f,D); - DumpConstants(f,D); - DumpCode(f,D); -} - -static void DumpHeader(DumpState* D) -{ - DumpLiteral(LUA_SIGNATURE,D); - DumpByte(VERSION,D); - DumpByte(luaU_endianness(),D); - DumpByte(sizeof(int),D); - DumpByte(sizeof(size_t),D); - DumpByte(sizeof(Instruction),D); - DumpByte(SIZE_OP,D); - DumpByte(SIZE_A,D); - DumpByte(SIZE_B,D); - DumpByte(SIZE_C,D); - DumpByte(sizeof(lua_Number),D); - DumpNumber(TEST_NUMBER,D); -} - -/* -** dump function as precompiled chunk -*/ -void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data) -{ - DumpState D; - D.L=L; - D.write=w; - D.data=data; - DumpHeader(&D); - DumpFunction(Main,NULL,&D); -} - +/*
+** $Id: ldump.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** save bytecodes
+** See Copyright Notice in lua.h
+*/
+
+#include <stddef.h>
+
+#define ldump_c
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lundump.h"
+
+#define DumpVector(b,n,size,D) DumpBlock(b,(n)*(size),D)
+#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D)
+
+typedef struct {
+ lua_State* L;
+ lua_Chunkwriter write;
+ void* data;
+} DumpState;
+
+static void DumpBlock(const void* b, size_t size, DumpState* D)
+{
+ lua_unlock(D->L);
+ (*D->write)(D->L,b,size,D->data);
+ lua_lock(D->L);
+}
+
+static void DumpByte(int y, DumpState* D)
+{
+ char x=(char)y;
+ DumpBlock(&x,sizeof(x),D);
+}
+
+static void DumpInt(int x, DumpState* D)
+{
+ DumpBlock(&x,sizeof(x),D);
+}
+
+static void DumpSize(size_t x, DumpState* D)
+{
+ DumpBlock(&x,sizeof(x),D);
+}
+
+static void DumpNumber(lua_Number x, DumpState* D)
+{
+ DumpBlock(&x,sizeof(x),D);
+}
+
+static void DumpString(TString* s, DumpState* D)
+{
+ if (s==NULL || getstr(s)==NULL)
+ DumpSize(0,D);
+ else
+ {
+ size_t size=s->tsv.len+1; /* include trailing '\0' */
+ DumpSize(size,D);
+ DumpBlock(getstr(s),size,D);
+ }
+}
+
+static void DumpCode(const Proto* f, DumpState* D)
+{
+ DumpInt(f->sizecode,D);
+ DumpVector(f->code,f->sizecode,sizeof(*f->code),D);
+}
+
+static void DumpLocals(const Proto* f, DumpState* D)
+{
+ int i,n=f->sizelocvars;
+ DumpInt(n,D);
+ for (i=0; i<n; i++)
+ {
+ DumpString(f->locvars[i].varname,D);
+ DumpInt(f->locvars[i].startpc,D);
+ DumpInt(f->locvars[i].endpc,D);
+ }
+}
+
+static void DumpLines(const Proto* f, DumpState* D)
+{
+ DumpInt(f->sizelineinfo,D);
+ DumpVector(f->lineinfo,f->sizelineinfo,sizeof(*f->lineinfo),D);
+}
+
+static void DumpUpvalues(const Proto* f, DumpState* D)
+{
+ int i,n=f->sizeupvalues;
+ DumpInt(n,D);
+ for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
+}
+
+static void DumpFunction(const Proto* f, const TString* p, DumpState* D);
+
+static void DumpConstants(const Proto* f, DumpState* D)
+{
+ int i,n;
+ DumpInt(n=f->sizek,D);
+ for (i=0; i<n; i++)
+ {
+ const TObject* o=&f->k[i];
+ DumpByte(ttype(o),D);
+ switch (ttype(o))
+ {
+ case LUA_TNUMBER:
+ DumpNumber(nvalue(o),D);
+ break;
+ case LUA_TSTRING:
+ DumpString(tsvalue(o),D);
+ break;
+ case LUA_TNIL:
+ break;
+ default:
+ lua_assert(0); /* cannot happen */
+ break;
+ }
+ }
+ DumpInt(n=f->sizep,D);
+ for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D);
+}
+
+static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
+{
+ DumpString((f->source==p) ? NULL : f->source,D);
+ DumpInt(f->lineDefined,D);
+ DumpByte(f->nups,D);
+ DumpByte(f->numparams,D);
+ DumpByte(f->is_vararg,D);
+ DumpByte(f->maxstacksize,D);
+ DumpLines(f,D);
+ DumpLocals(f,D);
+ DumpUpvalues(f,D);
+ DumpConstants(f,D);
+ DumpCode(f,D);
+}
+
+static void DumpHeader(DumpState* D)
+{
+ DumpLiteral(LUA_SIGNATURE,D);
+ DumpByte(VERSION,D);
+ DumpByte(luaU_endianness(),D);
+ DumpByte(sizeof(int),D);
+ DumpByte(sizeof(size_t),D);
+ DumpByte(sizeof(Instruction),D);
+ DumpByte(SIZE_OP,D);
+ DumpByte(SIZE_A,D);
+ DumpByte(SIZE_B,D);
+ DumpByte(SIZE_C,D);
+ DumpByte(sizeof(lua_Number),D);
+ DumpNumber(TEST_NUMBER,D);
+}
+
+/*
+** dump function as precompiled chunk
+*/
+void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data)
+{
+ DumpState D;
+ D.L=L;
+ D.write=w;
+ D.data=data;
+ DumpHeader(&D);
+ DumpFunction(Main,NULL,&D);
+}
+
diff --git a/lib/lua/src/lfunc.c b/lib/lua/src/lfunc.c index eafd953..4e72e53 100644 --- a/lib/lua/src/lfunc.c +++ b/lib/lua/src/lfunc.c @@ -1,135 +1,135 @@ -/* -** $Id: lfunc.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Auxiliary functions to manipulate prototypes and closures -** See Copyright Notice in lua.h -*/ - - -#include <stdlib.h> - -#define lfunc_c - -#include "lua.h" - -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" - - -#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ - cast(int, sizeof(TObject)*((n)-1))) - -#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ - cast(int, sizeof(TObject *)*((n)-1))) - - - -Closure *luaF_newCclosure (lua_State *L, int nelems) { - Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); - c->c.isC = 1; - c->c.nupvalues = cast(lu_byte, nelems); - return c; -} - - -Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) { - Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems))); - luaC_link(L, valtogco(c), LUA_TFUNCTION); - c->l.isC = 0; - c->l.g = *e; - c->l.nupvalues = cast(lu_byte, nelems); - return c; -} - - -UpVal *luaF_findupval (lua_State *L, StkId level) { - GCObject **pp = &L->openupval; - UpVal *p; - UpVal *v; - while ((p = ngcotouv(*pp)) != NULL && p->v >= level) { - if (p->v == level) return p; - pp = &p->next; - } - v = luaM_new(L, UpVal); /* not found: create a new one */ - v->tt = LUA_TUPVAL; - v->marked = 1; /* open upvalues should not be collected */ - v->v = level; /* current value lives in the stack */ - v->next = *pp; /* chain it in the proper position */ - *pp = valtogco(v); - return v; -} - - -void luaF_close (lua_State *L, StkId level) { - UpVal *p; - while ((p = ngcotouv(L->openupval)) != NULL && p->v >= level) { - setobj(&p->value, p->v); /* save current value (write barrier) */ - p->v = &p->value; /* now current value lives here */ - L->openupval = p->next; /* remove from `open' list */ - luaC_link(L, valtogco(p), LUA_TUPVAL); - } -} - - -Proto *luaF_newproto (lua_State *L) { - Proto *f = luaM_new(L, Proto); - luaC_link(L, valtogco(f), LUA_TPROTO); - f->k = NULL; - f->sizek = 0; - f->p = NULL; - f->sizep = 0; - f->code = NULL; - f->sizecode = 0; - f->sizelineinfo = 0; - f->sizeupvalues = 0; - f->nups = 0; - f->upvalues = NULL; - f->numparams = 0; - f->is_vararg = 0; - f->maxstacksize = 0; - f->lineinfo = NULL; - f->sizelocvars = 0; - f->locvars = NULL; - f->lineDefined = 0; - f->source = NULL; - return f; -} - - -void luaF_freeproto (lua_State *L, Proto *f) { - luaM_freearray(L, f->code, f->sizecode, Instruction); - luaM_freearray(L, f->p, f->sizep, Proto *); - luaM_freearray(L, f->k, f->sizek, TObject); - luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); - luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); - luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); - luaM_freelem(L, f); -} - - -void luaF_freeclosure (lua_State *L, Closure *c) { - int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : - sizeLclosure(c->l.nupvalues); - luaM_free(L, c, size); -} - - -/* -** Look for n-th local variable at line `line' in function `func'. -** Returns NULL if not found. -*/ -const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { - int i; - for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) { - if (pc < f->locvars[i].endpc) { /* is variable active? */ - local_number--; - if (local_number == 0) - return getstr(f->locvars[i].varname); - } - } - return NULL; /* not found */ -} - +/*
+** $Id: lfunc.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#define lfunc_c
+
+#include "lua.h"
+
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
+ cast(int, sizeof(TObject)*((n)-1)))
+
+#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
+ cast(int, sizeof(TObject *)*((n)-1)))
+
+
+
+Closure *luaF_newCclosure (lua_State *L, int nelems) {
+ Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
+ luaC_link(L, valtogco(c), LUA_TFUNCTION);
+ c->c.isC = 1;
+ c->c.nupvalues = cast(lu_byte, nelems);
+ return c;
+}
+
+
+Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) {
+ Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
+ luaC_link(L, valtogco(c), LUA_TFUNCTION);
+ c->l.isC = 0;
+ c->l.g = *e;
+ c->l.nupvalues = cast(lu_byte, nelems);
+ return c;
+}
+
+
+UpVal *luaF_findupval (lua_State *L, StkId level) {
+ GCObject **pp = &L->openupval;
+ UpVal *p;
+ UpVal *v;
+ while ((p = ngcotouv(*pp)) != NULL && p->v >= level) {
+ if (p->v == level) return p;
+ pp = &p->next;
+ }
+ v = luaM_new(L, UpVal); /* not found: create a new one */
+ v->tt = LUA_TUPVAL;
+ v->marked = 1; /* open upvalues should not be collected */
+ v->v = level; /* current value lives in the stack */
+ v->next = *pp; /* chain it in the proper position */
+ *pp = valtogco(v);
+ return v;
+}
+
+
+void luaF_close (lua_State *L, StkId level) {
+ UpVal *p;
+ while ((p = ngcotouv(L->openupval)) != NULL && p->v >= level) {
+ setobj(&p->value, p->v); /* save current value (write barrier) */
+ p->v = &p->value; /* now current value lives here */
+ L->openupval = p->next; /* remove from `open' list */
+ luaC_link(L, valtogco(p), LUA_TUPVAL);
+ }
+}
+
+
+Proto *luaF_newproto (lua_State *L) {
+ Proto *f = luaM_new(L, Proto);
+ luaC_link(L, valtogco(f), LUA_TPROTO);
+ f->k = NULL;
+ f->sizek = 0;
+ f->p = NULL;
+ f->sizep = 0;
+ f->code = NULL;
+ f->sizecode = 0;
+ f->sizelineinfo = 0;
+ f->sizeupvalues = 0;
+ f->nups = 0;
+ f->upvalues = NULL;
+ f->numparams = 0;
+ f->is_vararg = 0;
+ f->maxstacksize = 0;
+ f->lineinfo = NULL;
+ f->sizelocvars = 0;
+ f->locvars = NULL;
+ f->lineDefined = 0;
+ f->source = NULL;
+ return f;
+}
+
+
+void luaF_freeproto (lua_State *L, Proto *f) {
+ luaM_freearray(L, f->code, f->sizecode, Instruction);
+ luaM_freearray(L, f->p, f->sizep, Proto *);
+ luaM_freearray(L, f->k, f->sizek, TObject);
+ luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
+ luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
+ luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
+ luaM_freelem(L, f);
+}
+
+
+void luaF_freeclosure (lua_State *L, Closure *c) {
+ int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
+ sizeLclosure(c->l.nupvalues);
+ luaM_free(L, c, size);
+}
+
+
+/*
+** Look for n-th local variable at line `line' in function `func'.
+** Returns NULL if not found.
+*/
+const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
+ int i;
+ for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
+ if (pc < f->locvars[i].endpc) { /* is variable active? */
+ local_number--;
+ if (local_number == 0)
+ return getstr(f->locvars[i].varname);
+ }
+ }
+ return NULL; /* not found */
+}
+
diff --git a/lib/lua/src/lgc.c b/lib/lua/src/lgc.c index 078cffa..f565df6 100644 --- a/lib/lua/src/lgc.c +++ b/lib/lua/src/lgc.c @@ -1,493 +1,493 @@ -/* -** $Id: lgc.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Garbage Collector -** See Copyright Notice in lua.h -*/ - -#include <string.h> - -#define lgc_c - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" - - -typedef struct GCState { - GCObject *tmark; /* list of marked objects to be traversed */ - GCObject *wk; /* list of traversed key-weak tables (to be cleared) */ - GCObject *wv; /* list of traversed value-weak tables */ - GCObject *wkv; /* list of traversed key-value weak tables */ - global_State *g; -} GCState; - - -/* -** some userful bit tricks -*/ -#define setbit(x,b) ((x) |= (1<<(b))) -#define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b)))) -#define testbit(x,b) ((x) & (1<<(b))) - -#define unmark(x) resetbit((x)->gch.marked, 0) -#define ismarked(x) ((x)->gch.marked & ((1<<4)|1)) - -#define stringmark(s) setbit((s)->tsv.marked, 0) - - -#define isfinalized(u) (!testbit((u)->uv.marked, 1)) -#define markfinalized(u) resetbit((u)->uv.marked, 1) - - -#define KEYWEAKBIT 1 -#define VALUEWEAKBIT 2 -#define KEYWEAK (1<<KEYWEAKBIT) -#define VALUEWEAK (1<<VALUEWEAKBIT) - - - -#define markobject(st,o) { checkconsistency(o); \ - if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); } - -#define condmarkobject(st,o,c) { checkconsistency(o); \ - if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \ - reallymarkobject(st,gcvalue(o)); } - -#define markvalue(st,t) { if (!ismarked(valtogco(t))) \ - reallymarkobject(st, valtogco(t)); } - - - -static void reallymarkobject (GCState *st, GCObject *o) { - lua_assert(!ismarked(o)); - setbit(o->gch.marked, 0); /* mark object */ - switch (o->gch.tt) { - case LUA_TUSERDATA: { - markvalue(st, gcotou(o)->uv.metatable); - break; - } - case LUA_TFUNCTION: { - gcotocl(o)->c.gclist = st->tmark; - st->tmark = o; - break; - } - case LUA_TTABLE: { - gcotoh(o)->gclist = st->tmark; - st->tmark = o; - break; - } - case LUA_TTHREAD: { - gcototh(o)->gclist = st->tmark; - st->tmark = o; - break; - } - case LUA_TPROTO: { - gcotop(o)->gclist = st->tmark; - st->tmark = o; - break; - } - default: lua_assert(o->gch.tt == LUA_TSTRING); - } -} - - -static void marktmu (GCState *st) { - GCObject *u; - for (u = st->g->tmudata; u; u = u->gch.next) { - unmark(u); /* may be marked, if left from previous GC */ - reallymarkobject(st, u); - } -} - - -/* move `dead' udata that need finalization to list `tmudata' */ -void luaC_separateudata (lua_State *L) { - GCObject **p = &G(L)->rootudata; - GCObject *curr; - GCObject *collected = NULL; /* to collect udata with gc event */ - GCObject **lastcollected = &collected; - while ((curr = *p) != NULL) { - lua_assert(curr->gch.tt == LUA_TUSERDATA); - if (ismarked(curr) || isfinalized(gcotou(curr))) - p = &curr->gch.next; /* don't bother with them */ - - else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) { - markfinalized(gcotou(curr)); /* don't need finalization */ - p = &curr->gch.next; - } - else { /* must call its gc method */ - *p = curr->gch.next; - curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ - *lastcollected = curr; - lastcollected = &curr->gch.next; - } - } - /* insert collected udata with gc event into `tmudata' list */ - *lastcollected = G(L)->tmudata; - G(L)->tmudata = collected; -} - - -static void removekey (Node *n) { - setnilvalue(gval(n)); /* remove corresponding value ... */ - if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ -} - - -static void traversetable (GCState *st, Table *h) { - int i; - int weakkey = 0; - int weakvalue = 0; - const TObject *mode; - markvalue(st, h->metatable); - lua_assert(h->lsizenode || h->node == st->g->dummynode); - mode = gfasttm(st->g, h->metatable, TM_MODE); - if (mode && ttisstring(mode)) { /* is there a weak mode? */ - weakkey = (strchr(svalue(mode), 'k') != NULL); - weakvalue = (strchr(svalue(mode), 'v') != NULL); - if (weakkey || weakvalue) { /* is really weak? */ - GCObject **weaklist; - h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ - h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) | - (weakvalue << VALUEWEAKBIT)); - weaklist = (weakkey && weakvalue) ? &st->wkv : - (weakkey) ? &st->wk : - &st->wv; - h->gclist = *weaklist; /* must be cleared after GC, ... */ - *weaklist = valtogco(h); /* ... so put in the appropriate list */ - } - } - if (!weakvalue) { - i = h->sizearray; - while (i--) - markobject(st, &h->array[i]); - } - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); - if (!ttisnil(gval(n))) { - lua_assert(!ttisnil(gkey(n))); - condmarkobject(st, gkey(n), !weakkey); - condmarkobject(st, gval(n), !weakvalue); - } - } -} - - -static void traverseproto (GCState *st, Proto *f) { - int i; - stringmark(f->source); - for (i=0; i<f->sizek; i++) { /* mark literal strings */ - if (ttisstring(f->k+i)) - stringmark(tsvalue(f->k+i)); - } - for (i=0; i<f->sizeupvalues; i++) /* mark upvalue names */ - stringmark(f->upvalues[i]); - for (i=0; i<f->sizep; i++) /* mark nested protos */ - markvalue(st, f->p[i]); - for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */ - stringmark(f->locvars[i].varname); - lua_assert(luaG_checkcode(f)); -} - - - -static void traverseclosure (GCState *st, Closure *cl) { - if (cl->c.isC) { - int i; - for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ - markobject(st, &cl->c.upvalue[i]); - } - else { - int i; - lua_assert(cl->l.nupvalues == cl->l.p->nups); - markvalue(st, hvalue(&cl->l.g)); - markvalue(st, cl->l.p); - for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */ - UpVal *u = cl->l.upvals[i]; - if (!u->marked) { - markobject(st, &u->value); - u->marked = 1; - } - } - } -} - - -static void checkstacksizes (lua_State *L, StkId max) { - int used = L->ci - L->base_ci; /* number of `ci' in use */ - if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) - luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ - else condhardstacktests(luaD_reallocCI(L, L->size_ci)); - used = max - L->stack; /* part of stack in use */ - if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) - luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ - else condhardstacktests(luaD_reallocstack(L, L->stacksize)); -} - - -static void traversestack (GCState *st, lua_State *L1) { - StkId o, lim; - CallInfo *ci; - markobject(st, gt(L1)); - lim = L1->top; - for (ci = L1->base_ci; ci <= L1->ci; ci++) { - lua_assert(ci->top <= L1->stack_last); - lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC)); - if (!(ci->state & CI_C) && lim < ci->top) - lim = ci->top; - } - for (o = L1->stack; o < L1->top; o++) - markobject(st, o); - for (; o <= lim; o++) - setnilvalue(o); - checkstacksizes(L1, lim); -} - - -static void propagatemarks (GCState *st) { - while (st->tmark) { /* traverse marked objects */ - switch (st->tmark->gch.tt) { - case LUA_TTABLE: { - Table *h = gcotoh(st->tmark); - st->tmark = h->gclist; - traversetable(st, h); - break; - } - case LUA_TFUNCTION: { - Closure *cl = gcotocl(st->tmark); - st->tmark = cl->c.gclist; - traverseclosure(st, cl); - break; - } - case LUA_TTHREAD: { - lua_State *th = gcototh(st->tmark); - st->tmark = th->gclist; - traversestack(st, th); - break; - } - case LUA_TPROTO: { - Proto *p = gcotop(st->tmark); - st->tmark = p->gclist; - traverseproto(st, p); - break; - } - default: lua_assert(0); - } - } -} - - -static int valismarked (const TObject *o) { - if (ttisstring(o)) - stringmark(tsvalue(o)); /* strings are `values', so are never weak */ - return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0); -} - - -/* -** clear collected keys from weaktables -*/ -static void cleartablekeys (GCObject *l) { - while (l) { - Table *h = gcotoh(l); - int i = sizenode(h); - lua_assert(h->marked & KEYWEAK); - while (i--) { - Node *n = gnode(h, i); - if (!valismarked(gkey(n))) /* key was collected? */ - removekey(n); /* remove entry from table */ - } - l = h->gclist; - } -} - - -/* -** clear collected values from weaktables -*/ -static void cleartablevalues (GCObject *l) { - while (l) { - Table *h = gcotoh(l); - int i = h->sizearray; - lua_assert(h->marked & VALUEWEAK); - while (i--) { - TObject *o = &h->array[i]; - if (!valismarked(o)) /* value was collected? */ - setnilvalue(o); /* remove value */ - } - i = sizenode(h); - while (i--) { - Node *n = gnode(h, i); - if (!valismarked(gval(n))) /* value was collected? */ - removekey(n); /* remove entry from table */ - } - l = h->gclist; - } -} - - -static void freeobj (lua_State *L, GCObject *o) { - switch (o->gch.tt) { - case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break; - case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break; - case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break; - case LUA_TTABLE: luaH_free(L, gcotoh(o)); break; - case LUA_TTHREAD: { - lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread); - luaE_freethread(L, gcototh(o)); - break; - } - case LUA_TSTRING: { - luaM_free(L, o, sizestring(gcotots(o)->tsv.len)); - break; - } - case LUA_TUSERDATA: { - luaM_free(L, o, sizeudata(gcotou(o)->uv.len)); - break; - } - default: lua_assert(0); - } -} - - -static int sweeplist (lua_State *L, GCObject **p, int limit) { - GCObject *curr; - int count = 0; /* number of collected items */ - while ((curr = *p) != NULL) { - if (curr->gch.marked > limit) { - unmark(curr); - p = &curr->gch.next; - } - else { - count++; - *p = curr->gch.next; - freeobj(L, curr); - } - } - return count; -} - - -static void sweepstrings (lua_State *L, int all) { - int i; - for (i=0; i<G(L)->strt.size; i++) { /* for each list */ - G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all); - } -} - - -static void checkSizes (lua_State *L) { - /* check size of string hash */ - if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) && - G(L)->strt.size > MINSTRTABSIZE*2) - luaS_resize(L, G(L)->strt.size/2); /* table is too big */ - /* check size of buffer */ - if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2; - luaZ_resizebuffer(L, &G(L)->buff, newsize); - } - G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ -} - - -static void do1gcTM (lua_State *L, Udata *udata) { - const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC); - if (tm != NULL) { - setobj2s(L->top, tm); - setuvalue(L->top+1, udata); - L->top += 2; - luaD_call(L, L->top - 2, 0); - } -} - - -void luaC_callGCTM (lua_State *L) { - lu_byte oldah = L->allowhook; - L->allowhook = 0; /* stop debug hooks during GC tag methods */ - L->top++; /* reserve space to keep udata while runs its gc method */ - while (G(L)->tmudata != NULL) { - GCObject *o = G(L)->tmudata; - Udata *udata = gcotou(o); - G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */ - udata->uv.next = G(L)->rootudata; /* return it to `root' list */ - G(L)->rootudata = o; - setuvalue(L->top - 1, udata); /* keep a reference to it */ - unmark(o); - markfinalized(udata); - do1gcTM(L, udata); - } - L->top--; - L->allowhook = oldah; /* restore hooks */ -} - - -void luaC_sweep (lua_State *L, int all) { - if (all) all = 256; /* larger than any mark */ - sweeplist(L, &G(L)->rootudata, all); - sweepstrings(L, all); - sweeplist(L, &G(L)->rootgc, all); -} - - -/* mark root set */ -static void markroot (GCState *st, lua_State *L) { - global_State *g = st->g; - markobject(st, defaultmeta(L)); - markobject(st, registry(L)); - traversestack(st, g->mainthread); - if (L != g->mainthread) /* another thread is running? */ - markvalue(st, L); /* cannot collect it */ -} - - -static void mark (lua_State *L) { - GCState st; - GCObject *wkv; - st.g = G(L); - st.tmark = NULL; - st.wkv = st.wk = st.wv = NULL; - markroot(&st, L); - propagatemarks(&st); /* mark all reachable objects */ - cleartablevalues(st.wkv); - cleartablevalues(st.wv); - wkv = st.wkv; /* keys must be cleared after preserving udata */ - st.wkv = NULL; - st.wv = NULL; - luaC_separateudata(L); /* separate userdata to be preserved */ - marktmu(&st); /* mark `preserved' userdata */ - propagatemarks(&st); /* remark, to propagate `preserveness' */ - cleartablekeys(wkv); - /* `propagatemarks' may resuscitate some weak tables; clear them too */ - cleartablekeys(st.wk); - cleartablevalues(st.wv); - cleartablekeys(st.wkv); - cleartablevalues(st.wkv); -} - - -void luaC_collectgarbage (lua_State *L) { - mark(L); - luaC_sweep(L, 0); - checkSizes(L); - luaC_callGCTM(L); -} - - -void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { - o->gch.next = G(L)->rootgc; - G(L)->rootgc = o; - o->gch.marked = 0; - o->gch.tt = tt; -} - +/*
+** $Id: lgc.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#include <string.h>
+
+#define lgc_c
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+typedef struct GCState {
+ GCObject *tmark; /* list of marked objects to be traversed */
+ GCObject *wk; /* list of traversed key-weak tables (to be cleared) */
+ GCObject *wv; /* list of traversed value-weak tables */
+ GCObject *wkv; /* list of traversed key-value weak tables */
+ global_State *g;
+} GCState;
+
+
+/*
+** some userful bit tricks
+*/
+#define setbit(x,b) ((x) |= (1<<(b)))
+#define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b))))
+#define testbit(x,b) ((x) & (1<<(b)))
+
+#define unmark(x) resetbit((x)->gch.marked, 0)
+#define ismarked(x) ((x)->gch.marked & ((1<<4)|1))
+
+#define stringmark(s) setbit((s)->tsv.marked, 0)
+
+
+#define isfinalized(u) (!testbit((u)->uv.marked, 1))
+#define markfinalized(u) resetbit((u)->uv.marked, 1)
+
+
+#define KEYWEAKBIT 1
+#define VALUEWEAKBIT 2
+#define KEYWEAK (1<<KEYWEAKBIT)
+#define VALUEWEAK (1<<VALUEWEAKBIT)
+
+
+
+#define markobject(st,o) { checkconsistency(o); \
+ if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); }
+
+#define condmarkobject(st,o,c) { checkconsistency(o); \
+ if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \
+ reallymarkobject(st,gcvalue(o)); }
+
+#define markvalue(st,t) { if (!ismarked(valtogco(t))) \
+ reallymarkobject(st, valtogco(t)); }
+
+
+
+static void reallymarkobject (GCState *st, GCObject *o) {
+ lua_assert(!ismarked(o));
+ setbit(o->gch.marked, 0); /* mark object */
+ switch (o->gch.tt) {
+ case LUA_TUSERDATA: {
+ markvalue(st, gcotou(o)->uv.metatable);
+ break;
+ }
+ case LUA_TFUNCTION: {
+ gcotocl(o)->c.gclist = st->tmark;
+ st->tmark = o;
+ break;
+ }
+ case LUA_TTABLE: {
+ gcotoh(o)->gclist = st->tmark;
+ st->tmark = o;
+ break;
+ }
+ case LUA_TTHREAD: {
+ gcototh(o)->gclist = st->tmark;
+ st->tmark = o;
+ break;
+ }
+ case LUA_TPROTO: {
+ gcotop(o)->gclist = st->tmark;
+ st->tmark = o;
+ break;
+ }
+ default: lua_assert(o->gch.tt == LUA_TSTRING);
+ }
+}
+
+
+static void marktmu (GCState *st) {
+ GCObject *u;
+ for (u = st->g->tmudata; u; u = u->gch.next) {
+ unmark(u); /* may be marked, if left from previous GC */
+ reallymarkobject(st, u);
+ }
+}
+
+
+/* move `dead' udata that need finalization to list `tmudata' */
+void luaC_separateudata (lua_State *L) {
+ GCObject **p = &G(L)->rootudata;
+ GCObject *curr;
+ GCObject *collected = NULL; /* to collect udata with gc event */
+ GCObject **lastcollected = &collected;
+ while ((curr = *p) != NULL) {
+ lua_assert(curr->gch.tt == LUA_TUSERDATA);
+ if (ismarked(curr) || isfinalized(gcotou(curr)))
+ p = &curr->gch.next; /* don't bother with them */
+
+ else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) {
+ markfinalized(gcotou(curr)); /* don't need finalization */
+ p = &curr->gch.next;
+ }
+ else { /* must call its gc method */
+ *p = curr->gch.next;
+ curr->gch.next = NULL; /* link `curr' at the end of `collected' list */
+ *lastcollected = curr;
+ lastcollected = &curr->gch.next;
+ }
+ }
+ /* insert collected udata with gc event into `tmudata' list */
+ *lastcollected = G(L)->tmudata;
+ G(L)->tmudata = collected;
+}
+
+
+static void removekey (Node *n) {
+ setnilvalue(gval(n)); /* remove corresponding value ... */
+ if (iscollectable(gkey(n)))
+ setttype(gkey(n), LUA_TNONE); /* dead key; remove it */
+}
+
+
+static void traversetable (GCState *st, Table *h) {
+ int i;
+ int weakkey = 0;
+ int weakvalue = 0;
+ const TObject *mode;
+ markvalue(st, h->metatable);
+ lua_assert(h->lsizenode || h->node == st->g->dummynode);
+ mode = gfasttm(st->g, h->metatable, TM_MODE);
+ if (mode && ttisstring(mode)) { /* is there a weak mode? */
+ weakkey = (strchr(svalue(mode), 'k') != NULL);
+ weakvalue = (strchr(svalue(mode), 'v') != NULL);
+ if (weakkey || weakvalue) { /* is really weak? */
+ GCObject **weaklist;
+ h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
+ h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) |
+ (weakvalue << VALUEWEAKBIT));
+ weaklist = (weakkey && weakvalue) ? &st->wkv :
+ (weakkey) ? &st->wk :
+ &st->wv;
+ h->gclist = *weaklist; /* must be cleared after GC, ... */
+ *weaklist = valtogco(h); /* ... so put in the appropriate list */
+ }
+ }
+ if (!weakvalue) {
+ i = h->sizearray;
+ while (i--)
+ markobject(st, &h->array[i]);
+ }
+ i = sizenode(h);
+ while (i--) {
+ Node *n = gnode(h, i);
+ if (!ttisnil(gval(n))) {
+ lua_assert(!ttisnil(gkey(n)));
+ condmarkobject(st, gkey(n), !weakkey);
+ condmarkobject(st, gval(n), !weakvalue);
+ }
+ }
+}
+
+
+static void traverseproto (GCState *st, Proto *f) {
+ int i;
+ stringmark(f->source);
+ for (i=0; i<f->sizek; i++) { /* mark literal strings */
+ if (ttisstring(f->k+i))
+ stringmark(tsvalue(f->k+i));
+ }
+ for (i=0; i<f->sizeupvalues; i++) /* mark upvalue names */
+ stringmark(f->upvalues[i]);
+ for (i=0; i<f->sizep; i++) /* mark nested protos */
+ markvalue(st, f->p[i]);
+ for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */
+ stringmark(f->locvars[i].varname);
+ lua_assert(luaG_checkcode(f));
+}
+
+
+
+static void traverseclosure (GCState *st, Closure *cl) {
+ if (cl->c.isC) {
+ int i;
+ for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
+ markobject(st, &cl->c.upvalue[i]);
+ }
+ else {
+ int i;
+ lua_assert(cl->l.nupvalues == cl->l.p->nups);
+ markvalue(st, hvalue(&cl->l.g));
+ markvalue(st, cl->l.p);
+ for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
+ UpVal *u = cl->l.upvals[i];
+ if (!u->marked) {
+ markobject(st, &u->value);
+ u->marked = 1;
+ }
+ }
+ }
+}
+
+
+static void checkstacksizes (lua_State *L, StkId max) {
+ int used = L->ci - L->base_ci; /* number of `ci' in use */
+ if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
+ luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
+ else condhardstacktests(luaD_reallocCI(L, L->size_ci));
+ used = max - L->stack; /* part of stack in use */
+ if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
+ luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
+ else condhardstacktests(luaD_reallocstack(L, L->stacksize));
+}
+
+
+static void traversestack (GCState *st, lua_State *L1) {
+ StkId o, lim;
+ CallInfo *ci;
+ markobject(st, gt(L1));
+ lim = L1->top;
+ for (ci = L1->base_ci; ci <= L1->ci; ci++) {
+ lua_assert(ci->top <= L1->stack_last);
+ lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC));
+ if (!(ci->state & CI_C) && lim < ci->top)
+ lim = ci->top;
+ }
+ for (o = L1->stack; o < L1->top; o++)
+ markobject(st, o);
+ for (; o <= lim; o++)
+ setnilvalue(o);
+ checkstacksizes(L1, lim);
+}
+
+
+static void propagatemarks (GCState *st) {
+ while (st->tmark) { /* traverse marked objects */
+ switch (st->tmark->gch.tt) {
+ case LUA_TTABLE: {
+ Table *h = gcotoh(st->tmark);
+ st->tmark = h->gclist;
+ traversetable(st, h);
+ break;
+ }
+ case LUA_TFUNCTION: {
+ Closure *cl = gcotocl(st->tmark);
+ st->tmark = cl->c.gclist;
+ traverseclosure(st, cl);
+ break;
+ }
+ case LUA_TTHREAD: {
+ lua_State *th = gcototh(st->tmark);
+ st->tmark = th->gclist;
+ traversestack(st, th);
+ break;
+ }
+ case LUA_TPROTO: {
+ Proto *p = gcotop(st->tmark);
+ st->tmark = p->gclist;
+ traverseproto(st, p);
+ break;
+ }
+ default: lua_assert(0);
+ }
+ }
+}
+
+
+static int valismarked (const TObject *o) {
+ if (ttisstring(o))
+ stringmark(tsvalue(o)); /* strings are `values', so are never weak */
+ return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0);
+}
+
+
+/*
+** clear collected keys from weaktables
+*/
+static void cleartablekeys (GCObject *l) {
+ while (l) {
+ Table *h = gcotoh(l);
+ int i = sizenode(h);
+ lua_assert(h->marked & KEYWEAK);
+ while (i--) {
+ Node *n = gnode(h, i);
+ if (!valismarked(gkey(n))) /* key was collected? */
+ removekey(n); /* remove entry from table */
+ }
+ l = h->gclist;
+ }
+}
+
+
+/*
+** clear collected values from weaktables
+*/
+static void cleartablevalues (GCObject *l) {
+ while (l) {
+ Table *h = gcotoh(l);
+ int i = h->sizearray;
+ lua_assert(h->marked & VALUEWEAK);
+ while (i--) {
+ TObject *o = &h->array[i];
+ if (!valismarked(o)) /* value was collected? */
+ setnilvalue(o); /* remove value */
+ }
+ i = sizenode(h);
+ while (i--) {
+ Node *n = gnode(h, i);
+ if (!valismarked(gval(n))) /* value was collected? */
+ removekey(n); /* remove entry from table */
+ }
+ l = h->gclist;
+ }
+}
+
+
+static void freeobj (lua_State *L, GCObject *o) {
+ switch (o->gch.tt) {
+ case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break;
+ case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break;
+ case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break;
+ case LUA_TTABLE: luaH_free(L, gcotoh(o)); break;
+ case LUA_TTHREAD: {
+ lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread);
+ luaE_freethread(L, gcototh(o));
+ break;
+ }
+ case LUA_TSTRING: {
+ luaM_free(L, o, sizestring(gcotots(o)->tsv.len));
+ break;
+ }
+ case LUA_TUSERDATA: {
+ luaM_free(L, o, sizeudata(gcotou(o)->uv.len));
+ break;
+ }
+ default: lua_assert(0);
+ }
+}
+
+
+static int sweeplist (lua_State *L, GCObject **p, int limit) {
+ GCObject *curr;
+ int count = 0; /* number of collected items */
+ while ((curr = *p) != NULL) {
+ if (curr->gch.marked > limit) {
+ unmark(curr);
+ p = &curr->gch.next;
+ }
+ else {
+ count++;
+ *p = curr->gch.next;
+ freeobj(L, curr);
+ }
+ }
+ return count;
+}
+
+
+static void sweepstrings (lua_State *L, int all) {
+ int i;
+ for (i=0; i<G(L)->strt.size; i++) { /* for each list */
+ G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all);
+ }
+}
+
+
+static void checkSizes (lua_State *L) {
+ /* check size of string hash */
+ if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) &&
+ G(L)->strt.size > MINSTRTABSIZE*2)
+ luaS_resize(L, G(L)->strt.size/2); /* table is too big */
+ /* check size of buffer */
+ if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
+ size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2;
+ luaZ_resizebuffer(L, &G(L)->buff, newsize);
+ }
+ G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */
+}
+
+
+static void do1gcTM (lua_State *L, Udata *udata) {
+ const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC);
+ if (tm != NULL) {
+ setobj2s(L->top, tm);
+ setuvalue(L->top+1, udata);
+ L->top += 2;
+ luaD_call(L, L->top - 2, 0);
+ }
+}
+
+
+void luaC_callGCTM (lua_State *L) {
+ lu_byte oldah = L->allowhook;
+ L->allowhook = 0; /* stop debug hooks during GC tag methods */
+ L->top++; /* reserve space to keep udata while runs its gc method */
+ while (G(L)->tmudata != NULL) {
+ GCObject *o = G(L)->tmudata;
+ Udata *udata = gcotou(o);
+ G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */
+ udata->uv.next = G(L)->rootudata; /* return it to `root' list */
+ G(L)->rootudata = o;
+ setuvalue(L->top - 1, udata); /* keep a reference to it */
+ unmark(o);
+ markfinalized(udata);
+ do1gcTM(L, udata);
+ }
+ L->top--;
+ L->allowhook = oldah; /* restore hooks */
+}
+
+
+void luaC_sweep (lua_State *L, int all) {
+ if (all) all = 256; /* larger than any mark */
+ sweeplist(L, &G(L)->rootudata, all);
+ sweepstrings(L, all);
+ sweeplist(L, &G(L)->rootgc, all);
+}
+
+
+/* mark root set */
+static void markroot (GCState *st, lua_State *L) {
+ global_State *g = st->g;
+ markobject(st, defaultmeta(L));
+ markobject(st, registry(L));
+ traversestack(st, g->mainthread);
+ if (L != g->mainthread) /* another thread is running? */
+ markvalue(st, L); /* cannot collect it */
+}
+
+
+static void mark (lua_State *L) {
+ GCState st;
+ GCObject *wkv;
+ st.g = G(L);
+ st.tmark = NULL;
+ st.wkv = st.wk = st.wv = NULL;
+ markroot(&st, L);
+ propagatemarks(&st); /* mark all reachable objects */
+ cleartablevalues(st.wkv);
+ cleartablevalues(st.wv);
+ wkv = st.wkv; /* keys must be cleared after preserving udata */
+ st.wkv = NULL;
+ st.wv = NULL;
+ luaC_separateudata(L); /* separate userdata to be preserved */
+ marktmu(&st); /* mark `preserved' userdata */
+ propagatemarks(&st); /* remark, to propagate `preserveness' */
+ cleartablekeys(wkv);
+ /* `propagatemarks' may resuscitate some weak tables; clear them too */
+ cleartablekeys(st.wk);
+ cleartablevalues(st.wv);
+ cleartablekeys(st.wkv);
+ cleartablevalues(st.wkv);
+}
+
+
+void luaC_collectgarbage (lua_State *L) {
+ mark(L);
+ luaC_sweep(L, 0);
+ checkSizes(L);
+ luaC_callGCTM(L);
+}
+
+
+void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
+ o->gch.next = G(L)->rootgc;
+ G(L)->rootgc = o;
+ o->gch.marked = 0;
+ o->gch.tt = tt;
+}
+
diff --git a/lib/lua/src/llex.c b/lib/lua/src/llex.c index f7a5a26..6382cce 100644 --- a/lib/lua/src/llex.c +++ b/lib/lua/src/llex.c @@ -1,442 +1,442 @@ -/* -** $Id: llex.c,v 1.3 2003-12-11 16:53:30 pixel Exp $ -** Lexical Analyzer -** See Copyright Notice in lua.h -*/ - - -#include <ctype.h> -#include <string.h> - -#define llex_c - -#include "lua.h" - -#include "ldo.h" -#include "llex.h" -#include "lobject.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" -#include "lzio.h" - - - -#define next(LS) (LS->current = zgetc(LS->z)) - - - -/* ORDER RESERVED */ -static const char *const token2string [] = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "if", - "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", "*name", - "..", "...", "==", ">=", "<=", "~=", - "*number", "*string", "<eof>" -}; - - -void luaX_init (lua_State *L) { - int i; - for (i=0; i<NUM_RESERVED; i++) { - TString *ts = luaS_new(L, token2string[i]); - luaS_fix(ts); /* reserved words are never collected */ - lua_assert(strlen(token2string[i])+1 <= TOKEN_LEN); - ts->tsv.reserved = cast(lu_byte, i+1); /* reserved word */ - } -} - - -#define MAXSRC 80 - - -void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) { - if (val > limit) { - msg = luaO_pushfstring(ls->L, "too many %s (limit=%d)", msg, limit); - luaX_syntaxerror(ls, msg); - } -} - - -void luaX_errorline (LexState *ls, const char *s, const char *token, int line) { - lua_State *L = ls->L; - char buff[MAXSRC]; - luaO_chunkid(buff, getstr(ls->source), MAXSRC); - luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, line, s, token); - luaD_throw(L, LUA_ERRSYNTAX); -} - - -static void luaX_error (LexState *ls, const char *s, const char *token) { - luaX_errorline(ls, s, token, ls->linenumber); -} - - -void luaX_syntaxerror (LexState *ls, const char *msg) { - const char *lasttoken; - switch (ls->t.token) { - case TK_NAME: - lasttoken = getstr(ls->t.seminfo.ts); - break; - case TK_STRING: - case TK_NUMBER: - lasttoken = luaZ_buffer(ls->buff); - break; - default: - lasttoken = luaX_token2str(ls, ls->t.token); - break; - } - luaX_error(ls, msg, lasttoken); -} - - -const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { - lua_assert(token == (unsigned char)token); - return luaO_pushfstring(ls->L, "%c", token); - } - else - return token2string[token-FIRST_RESERVED]; -} - - -static void luaX_lexerror (LexState *ls, const char *s, int token) { - if (token == TK_EOS) - luaX_error(ls, s, luaX_token2str(ls, token)); - else - luaX_error(ls, s, luaZ_buffer(ls->buff)); -} - - -static void inclinenumber (LexState *LS) { - next(LS); /* skip `\n' */ - ++LS->linenumber; - luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk"); -} - - -void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) { - LS->L = L; - LS->lookahead.token = TK_EOS; /* no look-ahead token */ - LS->z = z; - LS->fs = NULL; - LS->linenumber = 1; - LS->lastline = 1; - LS->source = source; - next(LS); /* read first char */ - if (LS->current == '#') { - do { /* skip first line */ - next(LS); - } while (LS->current != '\n' && LS->current != EOZ); - } -} - - - -/* -** ======================================================= -** LEXICAL ANALYZER -** ======================================================= -*/ - - -/* use buffer to store names, literal strings and numbers */ - -/* extra space to allocate when growing buffer */ -#define EXTRABUFF 32 - -/* maximum number of chars that can be read without checking buffer size */ -#define MAXNOCHECK 5 - -#define checkbuffer(LS, len) \ - if (((len)+MAXNOCHECK)*sizeof(char) > luaZ_sizebuffer((LS)->buff)) \ - luaZ_openspace((LS)->L, (LS)->buff, (len)+EXTRABUFF) - -#define save(LS, c, l) \ - (luaZ_buffer((LS)->buff)[l++] = cast(char, c)) -#define save_and_next(LS, l) (save(LS, LS->current, l), next(LS)) - - -static size_t readname (LexState *LS) { - size_t l = 0; - checkbuffer(LS, l); - do { - checkbuffer(LS, l); - save_and_next(LS, l); - } while (isalnum(LS->current) || LS->current == '_'); - save(LS, '\0', l); - return l-1; -} - - -/* LUA_NUMBER */ -static void read_numeral (LexState *LS, int comma, SemInfo *seminfo) { - int oct = 0, hex = 0; - size_t l = 0; - checkbuffer(LS, l); - if (comma) save(LS, '.', l); - else if (LS->current == '0') { - oct = 1; - checkbuffer(LS, 1); - save_and_next(LS, l); - if (LS->current == 'x') { - oct = 0; - hex = 1; - checkbuffer(LS, 1); - save_and_next(LS, l); - } - } - while (isdigit(LS->current) || (hex && isxdigit(LS->current))) { - checkbuffer(LS, l); - save_and_next(LS, l); - } - checkbuffer(LS, 1); - if (LS->current == '.') { - save_and_next(LS, l); - if (hex || oct) { - save(LS, '\0', l); - luaX_lexerror(LS, - "error in number, mixing decimal point with octal or hexadecimal", - TK_NUMBER); - } - if (LS->current == '.') { - save_and_next(LS, l); - save(LS, '\0', l); - luaX_lexerror(LS, - "ambiguous syntax (decimal point x string concatenation)", - TK_NUMBER); - } - } - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); - } - if (LS->current == 'e' || LS->current == 'E') { - save_and_next(LS, l); /* read `E' */ - if (hex || oct) { - save(LS, '\0', l); - luaX_lexerror(LS, - "error in number, mixing exponential with octal or hexadecimal", - TK_NUMBER); - } - if (LS->current == '+' || LS->current == '-') - save_and_next(LS, l); /* optional exponent sign */ - while (isdigit(LS->current)) { - checkbuffer(LS, l); - save_and_next(LS, l); - } - } - save(LS, '\0', l); - if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r)) - luaX_lexerror(LS, "malformed number", TK_NUMBER); -} - - -static void read_long_string (LexState *LS, SemInfo *seminfo) { - int cont = 0; - size_t l = 0; - checkbuffer(LS, l); - save(LS, '[', l); /* save first `[' */ - save_and_next(LS, l); /* pass the second `[' */ - if (LS->current == '\n') /* string starts with a newline? */ - inclinenumber(LS); /* skip it */ - for (;;) { - checkbuffer(LS, l); - switch (LS->current) { - case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, (seminfo) ? "unfinished long string" : - "unfinished long comment", TK_EOS); - break; /* to avoid warnings */ - case '[': - save_and_next(LS, l); - if (LS->current == '[') { - cont++; - save_and_next(LS, l); - } - continue; - case ']': - save_and_next(LS, l); - if (LS->current == ']') { - if (cont == 0) goto endloop; - cont--; - save_and_next(LS, l); - } - continue; - case '\n': - save(LS, '\n', l); - inclinenumber(LS); - if (!seminfo) l = 0; /* reset buffer to avoid wasting space */ - continue; - default: - save_and_next(LS, l); - } - } endloop: - save_and_next(LS, l); /* skip the second `]' */ - save(LS, '\0', l); - if (seminfo) - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 2, l - 5); -} - - -static void read_string (LexState *LS, int del, SemInfo *seminfo) { - size_t l = 0; - checkbuffer(LS, l); - save_and_next(LS, l); - while (LS->current != del) { - checkbuffer(LS, l); - switch (LS->current) { - case EOZ: - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_EOS); - break; /* to avoid warnings */ - case '\n': - save(LS, '\0', l); - luaX_lexerror(LS, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': - next(LS); /* do not save the `\' */ - switch (LS->current) { - case 'a': save(LS, '\a', l); next(LS); break; - case 'b': save(LS, '\b', l); next(LS); break; - case 'f': save(LS, '\f', l); next(LS); break; - case 'n': save(LS, '\n', l); next(LS); break; - case 'r': save(LS, '\r', l); next(LS); break; - case 't': save(LS, '\t', l); next(LS); break; - case 'v': save(LS, '\v', l); next(LS); break; - case '\n': save(LS, '\n', l); inclinenumber(LS); break; - case EOZ: break; /* will raise an error next loop */ - default: { - if (!isdigit(LS->current)) - save_and_next(LS, l); /* handles \\, \", \', and \? */ - else { /* \xxx */ - int c = 0; - int i = 0; - do { - c = 10*c + (LS->current-'0'); - next(LS); - } while (++i<3 && isdigit(LS->current)); - if (c > UCHAR_MAX) { - save(LS, '\0', l); - luaX_lexerror(LS, "escape sequence too large", TK_STRING); - } - save(LS, c, l); - } - } - } - break; - default: - save_and_next(LS, l); - } - } - save_and_next(LS, l); /* skip delimiter */ - save(LS, '\0', l); - seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 1, l - 3); -} - - -int luaX_lex (LexState *LS, SemInfo *seminfo) { - for (;;) { - switch (LS->current) { - - case '\n': { - inclinenumber(LS); - continue; - } - case '-': { - next(LS); - if (LS->current != '-') return '-'; - /* else is a comment */ - next(LS); - if (LS->current == '[' && (next(LS), LS->current == '[')) - read_long_string(LS, NULL); /* long comment */ - else /* short comment */ - while (LS->current != '\n' && LS->current != EOZ) - next(LS); - continue; - } - case '[': { - next(LS); - if (LS->current != '[') return '['; - else { - read_long_string(LS, seminfo); - return TK_STRING; - } - } - case '=': { - next(LS); - if (LS->current != '=') return '='; - else { next(LS); return TK_EQ; } - } - case '<': { - next(LS); - if (LS->current != '=') return '<'; - else { next(LS); return TK_LE; } - } - case '>': { - next(LS); - if (LS->current != '=') return '>'; - else { next(LS); return TK_GE; } - } - case '~': { - next(LS); - if (LS->current != '=') return '~'; - else { next(LS); return TK_NE; } - } - case '"': - case '\'': { - read_string(LS, LS->current, seminfo); - return TK_STRING; - } - case '.': { - next(LS); - if (LS->current == '.') { - next(LS); - if (LS->current == '.') { - next(LS); - return TK_DOTS; /* ... */ - } - else return TK_CONCAT; /* .. */ - } - else if (!isdigit(LS->current)) return '.'; - else { - read_numeral(LS, 1, seminfo); - return TK_NUMBER; - } - } - case EOZ: { - return TK_EOS; - } - default: { - if (isspace(LS->current)) { - next(LS); - continue; - } - else if (isdigit(LS->current)) { - read_numeral(LS, 0, seminfo); - return TK_NUMBER; - } - else if (isalpha(LS->current) || LS->current == '_') { - /* identifier or reserved word */ - size_t l = readname(LS); - TString *ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff), l); - if (ts->tsv.reserved > 0) /* reserved word? */ - return ts->tsv.reserved - 1 + FIRST_RESERVED; - seminfo->ts = ts; - return TK_NAME; - } - else { - int c = LS->current; - if (iscntrl(c)) - luaX_error(LS, "invalid control char", - luaO_pushfstring(LS->L, "char(%d)", c)); - next(LS); - return c; /* single-char tokens (+ - / ...) */ - } - } - } - } -} - -#undef next +/*
+** $Id: llex.c,v 1.4 2004-11-27 21:35:20 pixel Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <string.h>
+
+#define llex_c
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "llex.h"
+#include "lobject.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "lzio.h"
+
+
+
+#define next(LS) (LS->current = zgetc(LS->z))
+
+
+
+/* ORDER RESERVED */
+static const char *const token2string [] = {
+ "and", "break", "do", "else", "elseif",
+ "end", "false", "for", "function", "if",
+ "in", "local", "nil", "not", "or", "repeat",
+ "return", "then", "true", "until", "while", "*name",
+ "..", "...", "==", ">=", "<=", "~=",
+ "*number", "*string", "<eof>"
+};
+
+
+void luaX_init (lua_State *L) {
+ int i;
+ for (i=0; i<NUM_RESERVED; i++) {
+ TString *ts = luaS_new(L, token2string[i]);
+ luaS_fix(ts); /* reserved words are never collected */
+ lua_assert(strlen(token2string[i])+1 <= TOKEN_LEN);
+ ts->tsv.reserved = cast(lu_byte, i+1); /* reserved word */
+ }
+}
+
+
+#define MAXSRC 80
+
+
+void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) {
+ if (val > limit) {
+ msg = luaO_pushfstring(ls->L, "too many %s (limit=%d)", msg, limit);
+ luaX_syntaxerror(ls, msg);
+ }
+}
+
+
+void luaX_errorline (LexState *ls, const char *s, const char *token, int line) {
+ lua_State *L = ls->L;
+ char buff[MAXSRC];
+ luaO_chunkid(buff, getstr(ls->source), MAXSRC);
+ luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, line, s, token);
+ luaD_throw(L, LUA_ERRSYNTAX);
+}
+
+
+static void luaX_error (LexState *ls, const char *s, const char *token) {
+ luaX_errorline(ls, s, token, ls->linenumber);
+}
+
+
+void luaX_syntaxerror (LexState *ls, const char *msg) {
+ const char *lasttoken;
+ switch (ls->t.token) {
+ case TK_NAME:
+ lasttoken = getstr(ls->t.seminfo.ts);
+ break;
+ case TK_STRING:
+ case TK_NUMBER:
+ lasttoken = luaZ_buffer(ls->buff);
+ break;
+ default:
+ lasttoken = luaX_token2str(ls, ls->t.token);
+ break;
+ }
+ luaX_error(ls, msg, lasttoken);
+}
+
+
+const char *luaX_token2str (LexState *ls, int token) {
+ if (token < FIRST_RESERVED) {
+ lua_assert(token == (unsigned char)token);
+ return luaO_pushfstring(ls->L, "%c", token);
+ }
+ else
+ return token2string[token-FIRST_RESERVED];
+}
+
+
+static void luaX_lexerror (LexState *ls, const char *s, int token) {
+ if (token == TK_EOS)
+ luaX_error(ls, s, luaX_token2str(ls, token));
+ else
+ luaX_error(ls, s, luaZ_buffer(ls->buff));
+}
+
+
+static void inclinenumber (LexState *LS) {
+ next(LS); /* skip `\n' */
+ ++LS->linenumber;
+ luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk");
+}
+
+
+void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) {
+ LS->L = L;
+ LS->lookahead.token = TK_EOS; /* no look-ahead token */
+ LS->z = z;
+ LS->fs = NULL;
+ LS->linenumber = 1;
+ LS->lastline = 1;
+ LS->source = source;
+ next(LS); /* read first char */
+ if (LS->current == '#') {
+ do { /* skip first line */
+ next(LS);
+ } while (LS->current != '\n' && LS->current != EOZ);
+ }
+}
+
+
+
+/*
+** =======================================================
+** LEXICAL ANALYZER
+** =======================================================
+*/
+
+
+/* use buffer to store names, literal strings and numbers */
+
+/* extra space to allocate when growing buffer */
+#define EXTRABUFF 32
+
+/* maximum number of chars that can be read without checking buffer size */
+#define MAXNOCHECK 5
+
+#define checkbuffer(LS, len) \
+ if (((len)+MAXNOCHECK)*sizeof(char) > luaZ_sizebuffer((LS)->buff)) \
+ luaZ_openspace((LS)->L, (LS)->buff, (len)+EXTRABUFF)
+
+#define save(LS, c, l) \
+ (luaZ_buffer((LS)->buff)[l++] = cast(char, c))
+#define save_and_next(LS, l) (save(LS, LS->current, l), next(LS))
+
+
+static size_t readname (LexState *LS) {
+ size_t l = 0;
+ checkbuffer(LS, l);
+ do {
+ checkbuffer(LS, l);
+ save_and_next(LS, l);
+ } while (isalnum(LS->current) || LS->current == '_');
+ save(LS, '\0', l);
+ return l-1;
+}
+
+
+/* LUA_NUMBER */
+static void read_numeral (LexState *LS, int comma, SemInfo *seminfo) {
+ int oct = 0, hex = 0;
+ size_t l = 0;
+ checkbuffer(LS, l);
+ if (comma) save(LS, '.', l);
+ else if (LS->current == '0') {
+ oct = 1;
+ checkbuffer(LS, 1);
+ save_and_next(LS, l);
+ if (LS->current == 'x') {
+ oct = 0;
+ hex = 1;
+ checkbuffer(LS, 1);
+ save_and_next(LS, l);
+ }
+ }
+ while (isdigit(LS->current) || (hex && isxdigit(LS->current))) {
+ checkbuffer(LS, l);
+ save_and_next(LS, l);
+ }
+ checkbuffer(LS, 1);
+ if (LS->current == '.') {
+ save_and_next(LS, l);
+ if (hex || oct) {
+ save(LS, '\0', l);
+ luaX_lexerror(LS,
+ "error in number, mixing decimal point with octal or hexadecimal",
+ TK_NUMBER);
+ }
+ if (LS->current == '.') {
+ save_and_next(LS, l);
+ save(LS, '\0', l);
+ luaX_lexerror(LS,
+ "ambiguous syntax (decimal point x string concatenation)",
+ TK_NUMBER);
+ }
+ }
+ while (isdigit(LS->current)) {
+ checkbuffer(LS, l);
+ save_and_next(LS, l);
+ }
+ if (LS->current == 'e' || LS->current == 'E') {
+ save_and_next(LS, l); /* read `E' */
+ if (hex || oct) {
+ save(LS, '\0', l);
+ luaX_lexerror(LS,
+ "error in number, mixing exponential with octal or hexadecimal",
+ TK_NUMBER);
+ }
+ if (LS->current == '+' || LS->current == '-')
+ save_and_next(LS, l); /* optional exponent sign */
+ while (isdigit(LS->current)) {
+ checkbuffer(LS, l);
+ save_and_next(LS, l);
+ }
+ }
+ save(LS, '\0', l);
+ if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r))
+ luaX_lexerror(LS, "malformed number", TK_NUMBER);
+}
+
+
+static void read_long_string (LexState *LS, SemInfo *seminfo) {
+ int cont = 0;
+ size_t l = 0;
+ checkbuffer(LS, l);
+ save(LS, '[', l); /* save first `[' */
+ save_and_next(LS, l); /* pass the second `[' */
+ if (LS->current == '\n') /* string starts with a newline? */
+ inclinenumber(LS); /* skip it */
+ for (;;) {
+ checkbuffer(LS, l);
+ switch (LS->current) {
+ case EOZ:
+ save(LS, '\0', l);
+ luaX_lexerror(LS, (seminfo) ? "unfinished long string" :
+ "unfinished long comment", TK_EOS);
+ break; /* to avoid warnings */
+ case '[':
+ save_and_next(LS, l);
+ if (LS->current == '[') {
+ cont++;
+ save_and_next(LS, l);
+ }
+ continue;
+ case ']':
+ save_and_next(LS, l);
+ if (LS->current == ']') {
+ if (cont == 0) goto endloop;
+ cont--;
+ save_and_next(LS, l);
+ }
+ continue;
+ case '\n':
+ save(LS, '\n', l);
+ inclinenumber(LS);
+ if (!seminfo) l = 0; /* reset buffer to avoid wasting space */
+ continue;
+ default:
+ save_and_next(LS, l);
+ }
+ } endloop:
+ save_and_next(LS, l); /* skip the second `]' */
+ save(LS, '\0', l);
+ if (seminfo)
+ seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 2, l - 5);
+}
+
+
+static void read_string (LexState *LS, int del, SemInfo *seminfo) {
+ size_t l = 0;
+ checkbuffer(LS, l);
+ save_and_next(LS, l);
+ while (LS->current != del) {
+ checkbuffer(LS, l);
+ switch (LS->current) {
+ case EOZ:
+ save(LS, '\0', l);
+ luaX_lexerror(LS, "unfinished string", TK_EOS);
+ break; /* to avoid warnings */
+ case '\n':
+ save(LS, '\0', l);
+ luaX_lexerror(LS, "unfinished string", TK_STRING);
+ break; /* to avoid warnings */
+ case '\\':
+ next(LS); /* do not save the `\' */
+ switch (LS->current) {
+ case 'a': save(LS, '\a', l); next(LS); break;
+ case 'b': save(LS, '\b', l); next(LS); break;
+ case 'f': save(LS, '\f', l); next(LS); break;
+ case 'n': save(LS, '\n', l); next(LS); break;
+ case 'r': save(LS, '\r', l); next(LS); break;
+ case 't': save(LS, '\t', l); next(LS); break;
+ case 'v': save(LS, '\v', l); next(LS); break;
+ case '\n': save(LS, '\n', l); inclinenumber(LS); break;
+ case EOZ: break; /* will raise an error next loop */
+ default: {
+ if (!isdigit(LS->current))
+ save_and_next(LS, l); /* handles \\, \", \', and \? */
+ else { /* \xxx */
+ int c = 0;
+ int i = 0;
+ do {
+ c = 10*c + (LS->current-'0');
+ next(LS);
+ } while (++i<3 && isdigit(LS->current));
+ if (c > UCHAR_MAX) {
+ save(LS, '\0', l);
+ luaX_lexerror(LS, "escape sequence too large", TK_STRING);
+ }
+ save(LS, c, l);
+ }
+ }
+ }
+ break;
+ default:
+ save_and_next(LS, l);
+ }
+ }
+ save_and_next(LS, l); /* skip delimiter */
+ save(LS, '\0', l);
+ seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 1, l - 3);
+}
+
+
+int luaX_lex (LexState *LS, SemInfo *seminfo) {
+ for (;;) {
+ switch (LS->current) {
+
+ case '\n': {
+ inclinenumber(LS);
+ continue;
+ }
+ case '-': {
+ next(LS);
+ if (LS->current != '-') return '-';
+ /* else is a comment */
+ next(LS);
+ if (LS->current == '[' && (next(LS), LS->current == '['))
+ read_long_string(LS, NULL); /* long comment */
+ else /* short comment */
+ while (LS->current != '\n' && LS->current != EOZ)
+ next(LS);
+ continue;
+ }
+ case '[': {
+ next(LS);
+ if (LS->current != '[') return '[';
+ else {
+ read_long_string(LS, seminfo);
+ return TK_STRING;
+ }
+ }
+ case '=': {
+ next(LS);
+ if (LS->current != '=') return '=';
+ else { next(LS); return TK_EQ; }
+ }
+ case '<': {
+ next(LS);
+ if (LS->current != '=') return '<';
+ else { next(LS); return TK_LE; }
+ }
+ case '>': {
+ next(LS);
+ if (LS->current != '=') return '>';
+ else { next(LS); return TK_GE; }
+ }
+ case '~': {
+ next(LS);
+ if (LS->current != '=') return '~';
+ else { next(LS); return TK_NE; }
+ }
+ case '"':
+ case '\'': {
+ read_string(LS, LS->current, seminfo);
+ return TK_STRING;
+ }
+ case '.': {
+ next(LS);
+ if (LS->current == '.') {
+ next(LS);
+ if (LS->current == '.') {
+ next(LS);
+ return TK_DOTS; /* ... */
+ }
+ else return TK_CONCAT; /* .. */
+ }
+ else if (!isdigit(LS->current)) return '.';
+ else {
+ read_numeral(LS, 1, seminfo);
+ return TK_NUMBER;
+ }
+ }
+ case EOZ: {
+ return TK_EOS;
+ }
+ default: {
+ if (isspace(LS->current)) {
+ next(LS);
+ continue;
+ }
+ else if (isdigit(LS->current)) {
+ read_numeral(LS, 0, seminfo);
+ return TK_NUMBER;
+ }
+ else if (isalpha(LS->current) || LS->current == '_') {
+ /* identifier or reserved word */
+ size_t l = readname(LS);
+ TString *ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff), l);
+ if (ts->tsv.reserved > 0) /* reserved word? */
+ return ts->tsv.reserved - 1 + FIRST_RESERVED;
+ seminfo->ts = ts;
+ return TK_NAME;
+ }
+ else {
+ int c = LS->current;
+ if (iscntrl(c))
+ luaX_error(LS, "invalid control char",
+ luaO_pushfstring(LS->L, "char(%d)", c));
+ next(LS);
+ return c; /* single-char tokens (+ - / ...) */
+ }
+ }
+ }
+ }
+}
+
+#undef next
diff --git a/lib/lua/src/lmem.c b/lib/lua/src/lmem.c index 9f047b9..e14f798 100644 --- a/lib/lua/src/lmem.c +++ b/lib/lua/src/lmem.c @@ -1,91 +1,91 @@ -/* -** $Id: lmem.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - - -#include <stdlib.h> - -#define lmem_c - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" - - - -/* -** definition for realloc function. It must assure that l_realloc(NULL, -** 0, x) allocates a new block (ANSI C assures that). (`os' is the old -** block size; some allocators may use that.) -*/ -#ifndef l_realloc -#define l_realloc(b,os,s) realloc(b,s) -#endif - -/* -** definition for free function. (`os' is the old block size; some -** allocators may use that.) -*/ -#ifndef l_free -#define l_free(b,os) free(b) -#endif - - -#define MINSIZEARRAY 4 - - -void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems, - int limit, const char *errormsg) { - void *newblock; - int newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - else if (*size >= limit/2) { /* cannot double it? */ - if (*size < limit - MINSIZEARRAY) /* try something smaller... */ - newsize = limit; /* still have at least MINSIZEARRAY free places */ - else luaG_runerror(L, errormsg); - } - newblock = luaM_realloc(L, block, - cast(lu_mem, *size)*cast(lu_mem, size_elems), - cast(lu_mem, newsize)*cast(lu_mem, size_elems)); - *size = newsize; /* update only when everything else is OK */ - return newblock; -} - - -/* -** generic allocation routine. -*/ -void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) { - lua_assert((oldsize == 0) == (block == NULL)); - if (size == 0) { - if (block != NULL) { - l_free(block, oldsize); - block = NULL; - } - else return NULL; /* avoid `nblocks' computations when oldsize==size==0 */ - } - else if (size >= MAX_SIZET) - luaG_runerror(L, "memory allocation error: block too big"); - else { - block = l_realloc(block, oldsize, size); - if (block == NULL) { - if (L) - luaD_throw(L, LUA_ERRMEM); - else return NULL; /* error before creating state! */ - } - } - if (L) { - lua_assert(G(L) != NULL && G(L)->nblocks > 0); - G(L)->nblocks -= oldsize; - G(L)->nblocks += size; - } - return block; -} - +/*
+** $Id: lmem.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#define lmem_c
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+/*
+** definition for realloc function. It must assure that l_realloc(NULL,
+** 0, x) allocates a new block (ANSI C assures that). (`os' is the old
+** block size; some allocators may use that.)
+*/
+#ifndef l_realloc
+#define l_realloc(b,os,s) realloc(b,s)
+#endif
+
+/*
+** definition for free function. (`os' is the old block size; some
+** allocators may use that.)
+*/
+#ifndef l_free
+#define l_free(b,os) free(b)
+#endif
+
+
+#define MINSIZEARRAY 4
+
+
+void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems,
+ int limit, const char *errormsg) {
+ void *newblock;
+ int newsize = (*size)*2;
+ if (newsize < MINSIZEARRAY)
+ newsize = MINSIZEARRAY; /* minimum size */
+ else if (*size >= limit/2) { /* cannot double it? */
+ if (*size < limit - MINSIZEARRAY) /* try something smaller... */
+ newsize = limit; /* still have at least MINSIZEARRAY free places */
+ else luaG_runerror(L, errormsg);
+ }
+ newblock = luaM_realloc(L, block,
+ cast(lu_mem, *size)*cast(lu_mem, size_elems),
+ cast(lu_mem, newsize)*cast(lu_mem, size_elems));
+ *size = newsize; /* update only when everything else is OK */
+ return newblock;
+}
+
+
+/*
+** generic allocation routine.
+*/
+void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) {
+ lua_assert((oldsize == 0) == (block == NULL));
+ if (size == 0) {
+ if (block != NULL) {
+ l_free(block, oldsize);
+ block = NULL;
+ }
+ else return NULL; /* avoid `nblocks' computations when oldsize==size==0 */
+ }
+ else if (size >= MAX_SIZET)
+ luaG_runerror(L, "memory allocation error: block too big");
+ else {
+ block = l_realloc(block, oldsize, size);
+ if (block == NULL) {
+ if (L)
+ luaD_throw(L, LUA_ERRMEM);
+ else return NULL; /* error before creating state! */
+ }
+ }
+ if (L) {
+ lua_assert(G(L) != NULL && G(L)->nblocks > 0);
+ G(L)->nblocks -= oldsize;
+ G(L)->nblocks += size;
+ }
+ return block;
+}
+
diff --git a/lib/lua/src/lobject.c b/lib/lua/src/lobject.c index 6a968eb..7153a1c 100644 --- a/lib/lua/src/lobject.c +++ b/lib/lua/src/lobject.c @@ -1,198 +1,198 @@ -/* -** $Id: lobject.c,v 1.3 2003-12-11 16:53:30 pixel Exp $ -** Some generic functions over Lua objects -** See Copyright Notice in lua.h -*/ - -#include <ctype.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> - -#define lobject_c - -#include "lua.h" - -#include "ldo.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "lvm.h" - -const TObject luaO_nilobject = {LUA_TNIL, {NULL}}; - - -/* -** converts an integer to a "floating point byte", represented as -** (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm) -*/ -int luaO_int2fb (unsigned int x) { - int m = 0; /* mantissa */ - while (x >= (1<<3)) { - x = (x+1) >> 1; - m++; - } - return (m << 3) | cast(int, x); -} - - -int luaO_log2 (unsigned int x) { - static const lu_byte log_8[255] = { - 0, - 1,1, - 2,2,2,2, - 3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 - }; - if (x >= 0x00010000) { - if (x >= 0x01000000) return log_8[((x>>24) & 0xff) - 1]+24; - else return log_8[((x>>16) & 0xff) - 1]+16; - } - else { - if (x >= 0x00000100) return log_8[((x>>8) & 0xff) - 1]+8; - else if (x) return log_8[(x & 0xff) - 1]; - return -1; /* special `log' for 0 */ - } -} - - -int luaO_rawequalObj (const TObject *t1, const TObject *t2) { - if (ttype(t1) != ttype(t2)) return 0; - else switch (ttype(t1)) { - case LUA_TNIL: - return 1; - case LUA_TNUMBER: - return nvalue(t1) == nvalue(t2); - case LUA_TBOOLEAN: - return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */ - case LUA_TLIGHTUSERDATA: - return pvalue(t1) == pvalue(t2); - default: - lua_assert(iscollectable(t1)); - return gcvalue(t1) == gcvalue(t2); - } -} - - -int luaO_str2d (const char *s, lua_Number *result) { - char *endptr; - size_t l = strlen(s); - lua_Number res; - if ((l > 0) && (s[0] == '0')) { - if ((l > 2) && (s[1] == 'x')) { - res = strtol(s + 2, &endptr, 16); - } else { - res = strtol(s + 1, &endptr, 8); - } - } else { - res = strtod(s, &endptr); - } - if (endptr == s) return 0; /* no conversion */ - while (isspace((unsigned char)(*endptr))) endptr++; - if (*endptr != '\0') return 0; /* invalid trailing characters? */ - *result = res; - return 1; -} - - - -static void pushstr (lua_State *L, const char *str) { - setsvalue2s(L->top, luaS_new(L, str)); - incr_top(L); -} - - -/* this function handles only `%d', `%c', %f, and `%s' formats */ -const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { - int n = 1; - pushstr(L, ""); - for (;;) { - const char *e = strchr(fmt, '%'); - if (e == NULL) break; - setsvalue2s(L->top, luaS_newlstr(L, fmt, e-fmt)); - incr_top(L); - switch (*(e+1)) { - case 's': - pushstr(L, va_arg(argp, char *)); - break; - case 'c': { - char buff[2]; - buff[0] = cast(char, va_arg(argp, int)); - buff[1] = '\0'; - pushstr(L, buff); - break; - } - case 'd': - setnvalue(L->top, cast(lua_Number, va_arg(argp, int))); - incr_top(L); - break; - case 'f': - setnvalue(L->top, cast(lua_Number, va_arg(argp, l_uacNumber))); - incr_top(L); - break; - case '%': - pushstr(L, "%"); - break; - default: lua_assert(0); - } - n += 2; - fmt = e+2; - } - pushstr(L, fmt); - luaV_concat(L, n+1, L->top - L->base - 1); - L->top -= n; - return svalue(L->top - 1); -} - - -const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { - const char *msg; - va_list argp; - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); - va_end(argp); - return msg; -} - - -void luaO_chunkid (char *out, const char *source, int bufflen) { - if (*source == '=') { - strncpy(out, source+1, bufflen); /* remove first char */ - out[bufflen-1] = '\0'; /* ensures null termination */ - } - else { /* out = "source", or "...source" */ - if (*source == '@') { - int l; - source++; /* skip the `@' */ - bufflen -= sizeof(" `...' "); - l = strlen(source); - strcpy(out, ""); - if (l>bufflen) { - source += (l-bufflen); /* get last part of file name */ - strcat(out, "..."); - } - strcat(out, source); - } - else { /* out = [string "string"] */ - int len = strcspn(source, "\n"); /* stop at first newline */ - bufflen -= sizeof(" [string \"...\"] "); - if (len > bufflen) len = bufflen; - strcpy(out, "[string \""); - if (source[len] != '\0') { /* must truncate? */ - strncat(out, source, len); - strcat(out, "..."); - } - else - strcat(out, source); - strcat(out, "\"]"); - } - } -} +/*
+** $Id: lobject.c,v 1.4 2004-11-27 21:35:20 pixel Exp $
+** Some generic functions over Lua objects
+** See Copyright Notice in lua.h
+*/
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define lobject_c
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "lvm.h"
+
+const TObject luaO_nilobject = {LUA_TNIL, {NULL}};
+
+
+/*
+** converts an integer to a "floating point byte", represented as
+** (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm)
+*/
+int luaO_int2fb (unsigned int x) {
+ int m = 0; /* mantissa */
+ while (x >= (1<<3)) {
+ x = (x+1) >> 1;
+ m++;
+ }
+ return (m << 3) | cast(int, x);
+}
+
+
+int luaO_log2 (unsigned int x) {
+ static const lu_byte log_8[255] = {
+ 0,
+ 1,1,
+ 2,2,2,2,
+ 3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+ };
+ if (x >= 0x00010000) {
+ if (x >= 0x01000000) return log_8[((x>>24) & 0xff) - 1]+24;
+ else return log_8[((x>>16) & 0xff) - 1]+16;
+ }
+ else {
+ if (x >= 0x00000100) return log_8[((x>>8) & 0xff) - 1]+8;
+ else if (x) return log_8[(x & 0xff) - 1];
+ return -1; /* special `log' for 0 */
+ }
+}
+
+
+int luaO_rawequalObj (const TObject *t1, const TObject *t2) {
+ if (ttype(t1) != ttype(t2)) return 0;
+ else switch (ttype(t1)) {
+ case LUA_TNIL:
+ return 1;
+ case LUA_TNUMBER:
+ return nvalue(t1) == nvalue(t2);
+ case LUA_TBOOLEAN:
+ return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */
+ case LUA_TLIGHTUSERDATA:
+ return pvalue(t1) == pvalue(t2);
+ default:
+ lua_assert(iscollectable(t1));
+ return gcvalue(t1) == gcvalue(t2);
+ }
+}
+
+
+int luaO_str2d (const char *s, lua_Number *result) {
+ char *endptr;
+ size_t l = strlen(s);
+ lua_Number res;
+ if ((l > 0) && (s[0] == '0')) {
+ if ((l > 2) && (s[1] == 'x')) {
+ res = strtol(s + 2, &endptr, 16);
+ } else {
+ res = strtol(s + 1, &endptr, 8);
+ }
+ } else {
+ res = strtod(s, &endptr);
+ }
+ if (endptr == s) return 0; /* no conversion */
+ while (isspace((unsigned char)(*endptr))) endptr++;
+ if (*endptr != '\0') return 0; /* invalid trailing characters? */
+ *result = res;
+ return 1;
+}
+
+
+
+static void pushstr (lua_State *L, const char *str) {
+ setsvalue2s(L->top, luaS_new(L, str));
+ incr_top(L);
+}
+
+
+/* this function handles only `%d', `%c', %f, and `%s' formats */
+const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
+ int n = 1;
+ pushstr(L, "");
+ for (;;) {
+ const char *e = strchr(fmt, '%');
+ if (e == NULL) break;
+ setsvalue2s(L->top, luaS_newlstr(L, fmt, e-fmt));
+ incr_top(L);
+ switch (*(e+1)) {
+ case 's':
+ pushstr(L, va_arg(argp, char *));
+ break;
+ case 'c': {
+ char buff[2];
+ buff[0] = cast(char, va_arg(argp, int));
+ buff[1] = '\0';
+ pushstr(L, buff);
+ break;
+ }
+ case 'd':
+ setnvalue(L->top, cast(lua_Number, va_arg(argp, int)));
+ incr_top(L);
+ break;
+ case 'f':
+ setnvalue(L->top, cast(lua_Number, va_arg(argp, l_uacNumber)));
+ incr_top(L);
+ break;
+ case '%':
+ pushstr(L, "%");
+ break;
+ default: lua_assert(0);
+ }
+ n += 2;
+ fmt = e+2;
+ }
+ pushstr(L, fmt);
+ luaV_concat(L, n+1, L->top - L->base - 1);
+ L->top -= n;
+ return svalue(L->top - 1);
+}
+
+
+const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
+ const char *msg;
+ va_list argp;
+ va_start(argp, fmt);
+ msg = luaO_pushvfstring(L, fmt, argp);
+ va_end(argp);
+ return msg;
+}
+
+
+void luaO_chunkid (char *out, const char *source, int bufflen) {
+ if (*source == '=') {
+ strncpy(out, source+1, bufflen); /* remove first char */
+ out[bufflen-1] = '\0'; /* ensures null termination */
+ }
+ else { /* out = "source", or "...source" */
+ if (*source == '@') {
+ int l;
+ source++; /* skip the `@' */
+ bufflen -= sizeof(" `...' ");
+ l = strlen(source);
+ strcpy(out, "");
+ if (l>bufflen) {
+ source += (l-bufflen); /* get last part of file name */
+ strcat(out, "...");
+ }
+ strcat(out, source);
+ }
+ else { /* out = [string "string"] */
+ int len = strcspn(source, "\n"); /* stop at first newline */
+ bufflen -= sizeof(" [string \"...\"] ");
+ if (len > bufflen) len = bufflen;
+ strcpy(out, "[string \"");
+ if (source[len] != '\0') { /* must truncate? */
+ strncat(out, source, len);
+ strcat(out, "...");
+ }
+ else
+ strcat(out, source);
+ strcat(out, "\"]");
+ }
+ }
+}
diff --git a/lib/lua/src/lopcodes.c b/lib/lua/src/lopcodes.c index 264b468..6d405d4 100644 --- a/lib/lua/src/lopcodes.c +++ b/lib/lua/src/lopcodes.c @@ -1,102 +1,102 @@ -/* -** $Id: lopcodes.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** extracted automatically from lopcodes.h by mkprint.lua -** DO NOT EDIT -** See Copyright Notice in lua.h -*/ - - -#define lopcodes_c - -#include "lua.h" - -#include "lobject.h" -#include "lopcodes.h" - - -#ifdef LUA_OPNAMES - -const char *const luaP_opnames[] = { - "MOVE", - "LOADK", - "LOADBOOL", - "LOADNIL", - "GETUPVAL", - "GETGLOBAL", - "GETTABLE", - "SETGLOBAL", - "SETUPVAL", - "SETTABLE", - "NEWTABLE", - "SELF", - "ADD", - "SUB", - "MUL", - "DIV", - "POW", - "UNM", - "NOT", - "CONCAT", - "JMP", - "EQ", - "LT", - "LE", - "TEST", - "CALL", - "TAILCALL", - "RETURN", - "FORLOOP", - "TFORLOOP", - "TFORPREP", - "SETLIST", - "SETLISTO", - "CLOSE", - "CLOSURE" -}; - -#endif - -#define opmode(t,b,bk,ck,sa,k,m) (((t)<<OpModeT) | \ - ((b)<<OpModeBreg) | ((bk)<<OpModeBrk) | ((ck)<<OpModeCrk) | \ - ((sa)<<OpModesetA) | ((k)<<OpModeK) | (m)) - - -const lu_byte luaP_opmodes[NUM_OPCODES] = { -/* T B Bk Ck sA K mode opcode */ - opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_MOVE */ - ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_LOADK */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_LOADNIL */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_GETUPVAL */ - ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_GETGLOBAL */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_GETTABLE */ - ,opmode(0, 0, 0, 0, 0, 1, iABx) /* OP_SETGLOBAL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */ - ,opmode(0, 0, 1, 1, 0, 0, iABC) /* OP_SETTABLE */ - ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_NEWTABLE */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_SELF */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_ADD */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_SUB */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_MUL */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_DIV */ - ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_POW */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_UNM */ - ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_NOT */ - ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_CONCAT */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_JMP */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_EQ */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LT */ - ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LE */ - ,opmode(1, 1, 0, 0, 1, 0, iABC) /* OP_TEST */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CALL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_TAILCALL */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_RETURN */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_FORLOOP */ - ,opmode(1, 0, 0, 0, 0, 0, iABC) /* OP_TFORLOOP */ - ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_TFORPREP */ - ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLIST */ - ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLISTO */ - ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CLOSE */ - ,opmode(0, 0, 0, 0, 1, 0, iABx) /* OP_CLOSURE */ -}; - +/*
+** $Id: lopcodes.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** extracted automatically from lopcodes.h by mkprint.lua
+** DO NOT EDIT
+** See Copyright Notice in lua.h
+*/
+
+
+#define lopcodes_c
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lopcodes.h"
+
+
+#ifdef LUA_OPNAMES
+
+const char *const luaP_opnames[] = {
+ "MOVE",
+ "LOADK",
+ "LOADBOOL",
+ "LOADNIL",
+ "GETUPVAL",
+ "GETGLOBAL",
+ "GETTABLE",
+ "SETGLOBAL",
+ "SETUPVAL",
+ "SETTABLE",
+ "NEWTABLE",
+ "SELF",
+ "ADD",
+ "SUB",
+ "MUL",
+ "DIV",
+ "POW",
+ "UNM",
+ "NOT",
+ "CONCAT",
+ "JMP",
+ "EQ",
+ "LT",
+ "LE",
+ "TEST",
+ "CALL",
+ "TAILCALL",
+ "RETURN",
+ "FORLOOP",
+ "TFORLOOP",
+ "TFORPREP",
+ "SETLIST",
+ "SETLISTO",
+ "CLOSE",
+ "CLOSURE"
+};
+
+#endif
+
+#define opmode(t,b,bk,ck,sa,k,m) (((t)<<OpModeT) | \
+ ((b)<<OpModeBreg) | ((bk)<<OpModeBrk) | ((ck)<<OpModeCrk) | \
+ ((sa)<<OpModesetA) | ((k)<<OpModeK) | (m))
+
+
+const lu_byte luaP_opmodes[NUM_OPCODES] = {
+/* T B Bk Ck sA K mode opcode */
+ opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_MOVE */
+ ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_LOADK */
+ ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_LOADBOOL */
+ ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_LOADNIL */
+ ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_GETUPVAL */
+ ,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_GETGLOBAL */
+ ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_GETTABLE */
+ ,opmode(0, 0, 0, 0, 0, 1, iABx) /* OP_SETGLOBAL */
+ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */
+ ,opmode(0, 0, 1, 1, 0, 0, iABC) /* OP_SETTABLE */
+ ,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_NEWTABLE */
+ ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_SELF */
+ ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_ADD */
+ ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_SUB */
+ ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_MUL */
+ ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_DIV */
+ ,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_POW */
+ ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_UNM */
+ ,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_NOT */
+ ,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_CONCAT */
+ ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_JMP */
+ ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_EQ */
+ ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LT */
+ ,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LE */
+ ,opmode(1, 1, 0, 0, 1, 0, iABC) /* OP_TEST */
+ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CALL */
+ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_TAILCALL */
+ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_RETURN */
+ ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_FORLOOP */
+ ,opmode(1, 0, 0, 0, 0, 0, iABC) /* OP_TFORLOOP */
+ ,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_TFORPREP */
+ ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLIST */
+ ,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLISTO */
+ ,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CLOSE */
+ ,opmode(0, 0, 0, 0, 1, 0, iABx) /* OP_CLOSURE */
+};
+
diff --git a/lib/lua/src/lparser.c b/lib/lua/src/lparser.c index 0645de3..2b557d4 100644 --- a/lib/lua/src/lparser.c +++ b/lib/lua/src/lparser.c @@ -1,1329 +1,1329 @@ -/* -** $Id: lparser.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - - -#include <string.h> - -#define lparser_c - -#include "lua.h" - -#include "lcode.h" -#include "ldebug.h" -#include "lfunc.h" -#include "llex.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lparser.h" -#include "lstate.h" -#include "lstring.h" - - - - -#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]]) - - -#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \ - luaX_syntaxerror(ls, "too many syntax levels"); -#define leavelevel(ls) ((ls)->nestlevel--) - - -/* -** nodes for block list (list of active blocks) -*/ -typedef struct BlockCnt { - struct BlockCnt *previous; /* chain */ - int breaklist; /* list of jumps out of this loop */ - int nactvar; /* # active local variables outside the breakable structure */ - int upval; /* true if some variable in the block is an upvalue */ - int isbreakable; /* true if `block' is a loop */ -} BlockCnt; - - - -/* -** prototypes for recursive non-terminal functions -*/ -static void chunk (LexState *ls); -static void expr (LexState *ls, expdesc *v); - - - -static void next (LexState *ls) { - ls->lastline = ls->linenumber; - if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ - ls->t = ls->lookahead; /* use this one */ - ls->lookahead.token = TK_EOS; /* and discharge it */ - } - else - ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */ -} - - -static void lookahead (LexState *ls) { - lua_assert(ls->lookahead.token == TK_EOS); - ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo); -} - - -static void error_expected (LexState *ls, int token) { - luaX_syntaxerror(ls, - luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token))); -} - - -static int testnext (LexState *ls, int c) { - if (ls->t.token == c) { - next(ls); - return 1; - } - else return 0; -} - - -static void check (LexState *ls, int c) { - if (!testnext(ls, c)) - error_expected(ls, c); -} - - -#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } - - - -static void check_match (LexState *ls, int what, int who, int where) { - if (!testnext(ls, what)) { - if (where == ls->linenumber) - error_expected(ls, what); - else { - luaX_syntaxerror(ls, luaO_pushfstring(ls->L, - "`%s' expected (to close `%s' at line %d)", - luaX_token2str(ls, what), luaX_token2str(ls, who), where)); - } - } -} - - -static TString *str_checkname (LexState *ls) { - TString *ts; - check_condition(ls, (ls->t.token == TK_NAME), "<name> expected"); - ts = ls->t.seminfo.ts; - next(ls); - return ts; -} - - -static void init_exp (expdesc *e, expkind k, int i) { - e->f = e->t = NO_JUMP; - e->k = k; - e->info = i; -} - - -static void codestring (LexState *ls, expdesc *e, TString *s) { - init_exp(e, VK, luaK_stringK(ls->fs, s)); -} - - -static void checkname(LexState *ls, expdesc *e) { - codestring(ls, e, str_checkname(ls)); -} - - -static int luaI_registerlocalvar (LexState *ls, TString *varname) { - FuncState *fs = ls->fs; - Proto *f = fs->f; - luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, - LocVar, MAX_INT, ""); - f->locvars[fs->nlocvars].varname = varname; - return fs->nlocvars++; -} - - -static void new_localvar (LexState *ls, TString *name, int n) { - FuncState *fs = ls->fs; - luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "local variables"); - fs->actvar[fs->nactvar+n] = luaI_registerlocalvar(ls, name); -} - - -static void adjustlocalvars (LexState *ls, int nvars) { - FuncState *fs = ls->fs; - fs->nactvar += nvars; - for (; nvars; nvars--) { - getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc; - } -} - - -static void removevars (LexState *ls, int tolevel) { - FuncState *fs = ls->fs; - while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar).endpc = fs->pc; -} - - -static void new_localvarstr (LexState *ls, const char *name, int n) { - new_localvar(ls, luaS_new(ls->L, name), n); -} - - -static void create_local (LexState *ls, const char *name) { - new_localvarstr(ls, name, 0); - adjustlocalvars(ls, 1); -} - - -static int indexupvalue (FuncState *fs, TString *name, expdesc *v) { - int i; - Proto *f = fs->f; - for (i=0; i<f->nups; i++) { - if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) { - lua_assert(fs->f->upvalues[i] == name); - return i; - } - } - /* new one */ - luaX_checklimit(fs->ls, f->nups + 1, MAXUPVALUES, "upvalues"); - luaM_growvector(fs->L, fs->f->upvalues, f->nups, fs->f->sizeupvalues, - TString *, MAX_INT, ""); - fs->f->upvalues[f->nups] = name; - fs->upvalues[f->nups] = *v; - return f->nups++; -} - - -static int searchvar (FuncState *fs, TString *n) { - int i; - for (i=fs->nactvar-1; i >= 0; i--) { - if (n == getlocvar(fs, i).varname) - return i; - } - return -1; /* not found */ -} - - -static void markupval (FuncState *fs, int level) { - BlockCnt *bl = fs->bl; - while (bl && bl->nactvar > level) bl = bl->previous; - if (bl) bl->upval = 1; -} - - -static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { - if (fs == NULL) /* no more levels? */ - init_exp(var, VGLOBAL, NO_REG); /* default is global variable */ - else { - int v = searchvar(fs, n); /* look up at current level */ - if (v >= 0) { - init_exp(var, VLOCAL, v); - if (!base) - markupval(fs, v); /* local will be used as an upval */ - } - else { /* not found at current level; try upper one */ - singlevaraux(fs->prev, n, var, 0); - if (var->k == VGLOBAL) { - if (base) - var->info = luaK_stringK(fs, n); /* info points to global name */ - } - else { /* LOCAL or UPVAL */ - var->info = indexupvalue(fs, n, var); - var->k = VUPVAL; /* upvalue in this level */ - } - } - } -} - - -static TString *singlevar (LexState *ls, expdesc *var, int base) { - TString *varname = str_checkname(ls); - singlevaraux(ls->fs, varname, var, base); - return varname; -} - - -static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { - FuncState *fs = ls->fs; - int extra = nvars - nexps; - if (e->k == VCALL) { - extra++; /* includes call itself */ - if (extra <= 0) extra = 0; - else luaK_reserveregs(fs, extra-1); - luaK_setcallreturns(fs, e, extra); /* call provides the difference */ - } - else { - if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ - if (extra > 0) { - int reg = fs->freereg; - luaK_reserveregs(fs, extra); - luaK_nil(fs, reg, extra); - } - } -} - - -static void code_params (LexState *ls, int nparams, int dots) { - FuncState *fs = ls->fs; - adjustlocalvars(ls, nparams); - luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters"); - fs->f->numparams = cast(lu_byte, fs->nactvar); - fs->f->is_vararg = cast(lu_byte, dots); - if (dots) - create_local(ls, "arg"); - luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ -} - - -static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { - bl->breaklist = NO_JUMP; - bl->isbreakable = isbreakable; - bl->nactvar = fs->nactvar; - bl->upval = 0; - bl->previous = fs->bl; - fs->bl = bl; - lua_assert(fs->freereg == fs->nactvar); -} - - -static void leaveblock (FuncState *fs) { - BlockCnt *bl = fs->bl; - fs->bl = bl->previous; - removevars(fs->ls, bl->nactvar); - if (bl->upval) - luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); - lua_assert(bl->nactvar == fs->nactvar); - fs->freereg = fs->nactvar; /* free registers */ - luaK_patchtohere(fs, bl->breaklist); -} - - -static void pushclosure (LexState *ls, FuncState *func, expdesc *v) { - FuncState *fs = ls->fs; - Proto *f = fs->f; - int i; - luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, - MAXARG_Bx, "constant table overflow"); - f->p[fs->np++] = func->f; - init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); - for (i=0; i<func->f->nups; i++) { - OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; - luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0); - } -} - - -static void open_func (LexState *ls, FuncState *fs) { - Proto *f = luaF_newproto(ls->L); - fs->f = f; - fs->prev = ls->fs; /* linked list of funcstates */ - fs->ls = ls; - fs->L = ls->L; - ls->fs = fs; - fs->pc = 0; - fs->lasttarget = 0; - fs->jpc = NO_JUMP; - fs->freereg = 0; - fs->nk = 0; - fs->h = luaH_new(ls->L, 0, 0); - fs->np = 0; - fs->nlocvars = 0; - fs->nactvar = 0; - fs->bl = NULL; - f->source = ls->source; - f->maxstacksize = 2; /* registers 0/1 are always valid */ -} - - -static void close_func (LexState *ls) { - lua_State *L = ls->L; - FuncState *fs = ls->fs; - Proto *f = fs->f; - removevars(ls, 0); - luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ - luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); - f->sizecode = fs->pc; - luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); - f->sizelineinfo = fs->pc; - luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject); - f->sizek = fs->nk; - luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); - f->sizep = fs->np; - luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); - f->sizelocvars = fs->nlocvars; - luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *); - f->sizeupvalues = f->nups; - lua_assert(luaG_checkcode(f)); - lua_assert(fs->bl == NULL); - ls->fs = fs->prev; -} - - -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) { - struct LexState lexstate; - struct FuncState funcstate; - lexstate.buff = buff; - lexstate.nestlevel = 0; - luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z))); - open_func(&lexstate, &funcstate); - next(&lexstate); /* read first token */ - chunk(&lexstate); - check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected"); - close_func(&lexstate); - lua_assert(funcstate.prev == NULL); - lua_assert(funcstate.f->nups == 0); - lua_assert(lexstate.nestlevel == 0); - return funcstate.f; -} - - - -/*============================================================*/ -/* GRAMMAR RULES */ -/*============================================================*/ - - -static void luaY_field (LexState *ls, expdesc *v) { - /* field -> ['.' | ':'] NAME */ - FuncState *fs = ls->fs; - expdesc key; - luaK_exp2anyreg(fs, v); - next(ls); /* skip the dot or colon */ - checkname(ls, &key); - luaK_indexed(fs, v, &key); -} - - -static void luaY_index (LexState *ls, expdesc *v) { - /* index -> '[' expr ']' */ - next(ls); /* skip the '[' */ - expr(ls, v); - luaK_exp2val(ls->fs, v); - check(ls, ']'); -} - - -/* -** {====================================================================== -** Rules for Constructors -** ======================================================================= -*/ - - -struct ConsControl { - expdesc v; /* last list item read */ - expdesc *t; /* table descriptor */ - int nh; /* total number of `record' elements */ - int na; /* total number of array elements */ - int tostore; /* number of array elements pending to be stored */ -}; - - -static void recfield (LexState *ls, struct ConsControl *cc) { - /* recfield -> (NAME | `['exp1`]') = exp1 */ - FuncState *fs = ls->fs; - int reg = ls->fs->freereg; - expdesc key, val; - if (ls->t.token == TK_NAME) { - luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor"); - cc->nh++; - checkname(ls, &key); - } - else /* ls->t.token == '[' */ - luaY_index(ls, &key); - check(ls, '='); - luaK_exp2RK(fs, &key); - expr(ls, &val); - luaK_codeABC(fs, OP_SETTABLE, cc->t->info, luaK_exp2RK(fs, &key), - luaK_exp2RK(fs, &val)); - fs->freereg = reg; /* free registers */ -} - - -static void closelistfield (FuncState *fs, struct ConsControl *cc) { - if (cc->v.k == VVOID) return; /* there is no list item */ - luaK_exp2nextreg(fs, &cc->v); - cc->v.k = VVOID; - if (cc->tostore == LFIELDS_PER_FLUSH) { - luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); /* flush */ - cc->tostore = 0; /* no more items pending */ - fs->freereg = cc->t->info + 1; /* free registers */ - } -} - - -static void lastlistfield (FuncState *fs, struct ConsControl *cc) { - if (cc->tostore == 0) return; - if (cc->v.k == VCALL) { - luaK_setcallreturns(fs, &cc->v, LUA_MULTRET); - luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1); - } - else { - if (cc->v.k != VVOID) - luaK_exp2nextreg(fs, &cc->v); - luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); - } - fs->freereg = cc->t->info + 1; /* free registers */ -} - - -static void listfield (LexState *ls, struct ConsControl *cc) { - expr(ls, &cc->v); - luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor"); - cc->na++; - cc->tostore++; -} - - -static void constructor (LexState *ls, expdesc *t) { - /* constructor -> ?? */ - FuncState *fs = ls->fs; - int line = ls->linenumber; - int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); - struct ConsControl cc; - cc.na = cc.nh = cc.tostore = 0; - cc.t = t; - init_exp(t, VRELOCABLE, pc); - init_exp(&cc.v, VVOID, 0); /* no value (yet) */ - luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */ - check(ls, '{'); - do { - lua_assert(cc.v.k == VVOID || cc.tostore > 0); - testnext(ls, ';'); /* compatibility only */ - if (ls->t.token == '}') break; - closelistfield(fs, &cc); - switch(ls->t.token) { - case TK_NAME: { /* may be listfields or recfields */ - lookahead(ls); - if (ls->lookahead.token != '=') /* expression? */ - listfield(ls, &cc); - else - recfield(ls, &cc); - break; - } - case '[': { /* constructor_item -> recfield */ - recfield(ls, &cc); - break; - } - default: { /* constructor_part -> listfield */ - listfield(ls, &cc); - break; - } - } - } while (testnext(ls, ',') || testnext(ls, ';')); - check_match(ls, '}', '{', line); - lastlistfield(fs, &cc); - SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ - SETARG_C(fs->f->code[pc], luaO_log2(cc.nh)+1); /* set initial table size */ -} - -/* }====================================================================== */ - - - -static void parlist (LexState *ls) { - /* parlist -> [ param { `,' param } ] */ - int nparams = 0; - int dots = 0; - if (ls->t.token != ')') { /* is `parlist' not empty? */ - do { - switch (ls->t.token) { - case TK_DOTS: dots = 1; next(ls); break; - case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break; - default: luaX_syntaxerror(ls, "<name> or `...' expected"); - } - } while (!dots && testnext(ls, ',')); - } - code_params(ls, nparams, dots); -} - - -static void body (LexState *ls, expdesc *e, int needself, int line) { - /* body -> `(' parlist `)' chunk END */ - FuncState new_fs; - open_func(ls, &new_fs); - new_fs.f->lineDefined = line; - check(ls, '('); - if (needself) - create_local(ls, "self"); - parlist(ls); - check(ls, ')'); - chunk(ls); - check_match(ls, TK_END, TK_FUNCTION, line); - close_func(ls); - pushclosure(ls, &new_fs, e); -} - - -static int explist1 (LexState *ls, expdesc *v) { - /* explist1 -> expr { `,' expr } */ - int n = 1; /* at least one expression */ - expr(ls, v); - while (testnext(ls, ',')) { - luaK_exp2nextreg(ls->fs, v); - expr(ls, v); - n++; - } - return n; -} - - -static void funcargs (LexState *ls, expdesc *f) { - FuncState *fs = ls->fs; - expdesc args; - int base, nparams; - int line = ls->linenumber; - switch (ls->t.token) { - case '(': { /* funcargs -> `(' [ explist1 ] `)' */ - if (line != ls->lastline) - luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); - next(ls); - if (ls->t.token == ')') /* arg list is empty? */ - args.k = VVOID; - else { - explist1(ls, &args); - luaK_setcallreturns(fs, &args, LUA_MULTRET); - } - check_match(ls, ')', '(', line); - break; - } - case '{': { /* funcargs -> constructor */ - constructor(ls, &args); - break; - } - case TK_STRING: { /* funcargs -> STRING */ - codestring(ls, &args, ls->t.seminfo.ts); - next(ls); /* must use `seminfo' before `next' */ - break; - } - default: { - luaX_syntaxerror(ls, "function arguments expected"); - return; - } - } - lua_assert(f->k == VNONRELOC); - base = f->info; /* base register for call */ - if (args.k == VCALL) - nparams = LUA_MULTRET; /* open call */ - else { - if (args.k != VVOID) - luaK_exp2nextreg(fs, &args); /* close last argument */ - nparams = fs->freereg - (base+1); - } - init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); - luaK_fixline(fs, line); - fs->freereg = base+1; /* call remove function and arguments and leaves - (unless changed) one result */ -} - - - - -/* -** {====================================================================== -** Expression parsing -** ======================================================================= -*/ - - -static void prefixexp (LexState *ls, expdesc *v) { - /* prefixexp -> NAME | '(' expr ')' */ - switch (ls->t.token) { - case '(': { - int line = ls->linenumber; - next(ls); - expr(ls, v); - check_match(ls, ')', '(', line); - luaK_dischargevars(ls->fs, v); - return; - } - case TK_NAME: { - singlevar(ls, v, 1); - return; - } -#ifdef LUA_COMPATUPSYNTAX - case '%': { /* for compatibility only */ - TString *varname; - int line = ls->linenumber; - next(ls); /* skip `%' */ - varname = singlevar(ls, v, 1); - if (v->k != VUPVAL) - luaX_errorline(ls, "global upvalues are obsolete", - getstr(varname), line); - return; - } -#endif - default: { - luaX_syntaxerror(ls, "unexpected symbol"); - return; - } - } -} - - -static void primaryexp (LexState *ls, expdesc *v) { - /* primaryexp -> - prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ - FuncState *fs = ls->fs; - prefixexp(ls, v); - for (;;) { - switch (ls->t.token) { - case '.': { /* field */ - luaY_field(ls, v); - break; - } - case '[': { /* `[' exp1 `]' */ - expdesc key; - luaK_exp2anyreg(fs, v); - luaY_index(ls, &key); - luaK_indexed(fs, v, &key); - break; - } - case ':': { /* `:' NAME funcargs */ - expdesc key; - next(ls); - checkname(ls, &key); - luaK_self(fs, v, &key); - funcargs(ls, v); - break; - } - case '(': case TK_STRING: case '{': { /* funcargs */ - luaK_exp2nextreg(fs, v); - funcargs(ls, v); - break; - } - default: return; - } - } -} - - -static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | constructor | FUNCTION body - | primaryexp */ - switch (ls->t.token) { - case TK_NUMBER: { - init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r)); - next(ls); /* must use `seminfo' before `next' */ - break; - } - case TK_STRING: { - codestring(ls, v, ls->t.seminfo.ts); - next(ls); /* must use `seminfo' before `next' */ - break; - } - case TK_NIL: { - init_exp(v, VNIL, 0); - next(ls); - break; - } - case TK_TRUE: { - init_exp(v, VTRUE, 0); - next(ls); - break; - } - case TK_FALSE: { - init_exp(v, VFALSE, 0); - next(ls); - break; - } - case '{': { /* constructor */ - constructor(ls, v); - break; - } - case TK_FUNCTION: { - next(ls); - body(ls, v, 0, ls->linenumber); - break; - } - default: { - primaryexp(ls, v); - break; - } - } -} - - -static UnOpr getunopr (int op) { - switch (op) { - case TK_NOT: return OPR_NOT; - case '-': return OPR_MINUS; - default: return OPR_NOUNOPR; - } -} - - -static BinOpr getbinopr (int op) { - switch (op) { - case '+': return OPR_ADD; - case '-': return OPR_SUB; - case '*': return OPR_MULT; - case '/': return OPR_DIV; - case '^': return OPR_POW; - case TK_CONCAT: return OPR_CONCAT; - case TK_NE: return OPR_NE; - case TK_EQ: return OPR_EQ; - case '<': return OPR_LT; - case TK_LE: return OPR_LE; - case '>': return OPR_GT; - case TK_GE: return OPR_GE; - case TK_AND: return OPR_AND; - case TK_OR: return OPR_OR; - default: return OPR_NOBINOPR; - } -} - - -static const struct { - lu_byte left; /* left priority for each binary operator */ - lu_byte right; /* right priority */ -} priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, /* arithmetic */ - {10, 9}, {5, 4}, /* power and concat (right associative) */ - {3, 3}, {3, 3}, /* equality */ - {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ - {2, 2}, {1, 1} /* logical (and/or) */ -}; - -#define UNARY_PRIORITY 8 /* priority for unary operators */ - - -/* -** subexpr -> (simplexep | unop subexpr) { binop subexpr } -** where `binop' is any binary operator with a priority higher than `limit' -*/ -static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { - BinOpr op; - UnOpr uop; - enterlevel(ls); - uop = getunopr(ls->t.token); - if (uop != OPR_NOUNOPR) { - next(ls); - subexpr(ls, v, UNARY_PRIORITY); - luaK_prefix(ls->fs, uop, v); - } - else simpleexp(ls, v); - /* expand while operators have priorities higher than `limit' */ - op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && cast(int, priority[op].left) > limit) { - expdesc v2; - BinOpr nextop; - next(ls); - luaK_infix(ls->fs, op, v); - /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, cast(int, priority[op].right)); - luaK_posfix(ls->fs, op, v, &v2); - op = nextop; - } - leavelevel(ls); - return op; /* return first untreated operator */ -} - - -static void expr (LexState *ls, expdesc *v) { - subexpr(ls, v, -1); -} - -/* }==================================================================== */ - - - -/* -** {====================================================================== -** Rules for Statements -** ======================================================================= -*/ - - -static int block_follow (int token) { - switch (token) { - case TK_ELSE: case TK_ELSEIF: case TK_END: - case TK_UNTIL: case TK_EOS: - return 1; - default: return 0; - } -} - - -static void block (LexState *ls) { - /* block -> chunk */ - FuncState *fs = ls->fs; - BlockCnt bl; - enterblock(fs, &bl, 0); - chunk(ls); - lua_assert(bl.breaklist == NO_JUMP); - leaveblock(fs); -} - - -/* -** structure to chain all variables in the left-hand side of an -** assignment -*/ -struct LHS_assign { - struct LHS_assign *prev; - expdesc v; /* variable (global, local, upvalue, or indexed) */ -}; - - -/* -** check whether, in an assignment to a local variable, the local variable -** is needed in a previous assignment (to a table). If so, save original -** local value in a safe place and use this safe copy in the previous -** assignment. -*/ -static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { - FuncState *fs = ls->fs; - int extra = fs->freereg; /* eventual position to save local variable */ - int conflict = 0; - for (; lh; lh = lh->prev) { - if (lh->v.k == VINDEXED) { - if (lh->v.info == v->info) { /* conflict? */ - conflict = 1; - lh->v.info = extra; /* previous assignment will use safe copy */ - } - if (lh->v.aux == v->info) { /* conflict? */ - conflict = 1; - lh->v.aux = extra; /* previous assignment will use safe copy */ - } - } - } - if (conflict) { - luaK_codeABC(fs, OP_MOVE, fs->freereg, v->info, 0); /* make copy */ - luaK_reserveregs(fs, 1); - } -} - - -static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { - expdesc e; - check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, - "syntax error"); - if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ - struct LHS_assign nv; - nv.prev = lh; - primaryexp(ls, &nv.v); - if (nv.v.k == VLOCAL) - check_conflict(ls, lh, &nv.v); - assignment(ls, &nv, nvars+1); - } - else { /* assignment -> `=' explist1 */ - int nexps; - check(ls, '='); - nexps = explist1(ls, &e); - if (nexps != nvars) { - adjust_assign(ls, nvars, nexps, &e); - if (nexps > nvars) - ls->fs->freereg -= nexps - nvars; /* remove extra values */ - } - else { - luaK_setcallreturns(ls->fs, &e, 1); /* close last expression */ - luaK_storevar(ls->fs, &lh->v, &e); - return; /* avoid default */ - } - } - init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ - luaK_storevar(ls->fs, &lh->v, &e); -} - - -static void cond (LexState *ls, expdesc *v) { - /* cond -> exp */ - expr(ls, v); /* read condition */ - if (v->k == VNIL) v->k = VFALSE; /* `falses' are all equal here */ - luaK_goiftrue(ls->fs, v); - luaK_patchtohere(ls->fs, v->t); -} - - -/* -** The while statement optimizes its code by coding the condition -** after its body (and thus avoiding one jump in the loop). -*/ - -/* -** maximum size of expressions for optimizing `while' code -*/ -#ifndef MAXEXPWHILE -#define MAXEXPWHILE 100 -#endif - -/* -** the call `luaK_goiffalse' may grow the size of an expression by -** at most this: -*/ -#define EXTRAEXP 5 - -static void whilestat (LexState *ls, int line) { - /* whilestat -> WHILE cond DO block END */ - Instruction codeexp[MAXEXPWHILE + EXTRAEXP]; - int lineexp; - int i; - int sizeexp; - FuncState *fs = ls->fs; - int whileinit, blockinit, expinit; - expdesc v; - BlockCnt bl; - next(ls); /* skip WHILE */ - whileinit = luaK_jump(fs); /* jump to condition (which will be moved) */ - expinit = luaK_getlabel(fs); - expr(ls, &v); /* parse condition */ - if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */ - lineexp = ls->linenumber; - luaK_goiffalse(fs, &v); - luaK_concat(fs, &v.f, fs->jpc); - fs->jpc = NO_JUMP; - sizeexp = fs->pc - expinit; /* size of expression code */ - if (sizeexp > MAXEXPWHILE) - luaX_syntaxerror(ls, "`while' condition too complex"); - for (i = 0; i < sizeexp; i++) /* save `exp' code */ - codeexp[i] = fs->f->code[expinit + i]; - fs->pc = expinit; /* remove `exp' code */ - enterblock(fs, &bl, 1); - check(ls, TK_DO); - blockinit = luaK_getlabel(fs); - block(ls); - luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ - /* move `exp' back to code */ - if (v.t != NO_JUMP) v.t += fs->pc - expinit; - if (v.f != NO_JUMP) v.f += fs->pc - expinit; - for (i=0; i<sizeexp; i++) - luaK_code(fs, codeexp[i], lineexp); - check_match(ls, TK_END, TK_WHILE, line); - leaveblock(fs); - luaK_patchlist(fs, v.t, blockinit); /* true conditions go back to loop */ - luaK_patchtohere(fs, v.f); /* false conditions finish the loop */ -} - - -static void repeatstat (LexState *ls, int line) { - /* repeatstat -> REPEAT block UNTIL cond */ - FuncState *fs = ls->fs; - int repeat_init = luaK_getlabel(fs); - expdesc v; - BlockCnt bl; - enterblock(fs, &bl, 1); - next(ls); - block(ls); - check_match(ls, TK_UNTIL, TK_REPEAT, line); - cond(ls, &v); - luaK_patchlist(fs, v.f, repeat_init); - leaveblock(fs); -} - - -static int exp1 (LexState *ls) { - expdesc e; - int k; - expr(ls, &e); - k = e.k; - luaK_exp2nextreg(ls->fs, &e); - return k; -} - - -static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { - BlockCnt bl; - FuncState *fs = ls->fs; - int prep, endfor; - adjustlocalvars(ls, nvars); /* scope for all variables */ - check(ls, TK_DO); - enterblock(fs, &bl, 1); /* loop block */ - prep = luaK_getlabel(fs); - block(ls); - luaK_patchtohere(fs, prep-1); - endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) : - luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); - luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep); - leaveblock(fs); -} - - -static void fornum (LexState *ls, TString *varname, int line) { - /* fornum -> NAME = exp1,exp1[,exp1] DO body */ - FuncState *fs = ls->fs; - int base = fs->freereg; - new_localvar(ls, varname, 0); - new_localvarstr(ls, "(for limit)", 1); - new_localvarstr(ls, "(for step)", 2); - check(ls, '='); - exp1(ls); /* initial value */ - check(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',')) - exp1(ls); /* optional step */ - else { /* default step = 1 */ - luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1)); - luaK_reserveregs(fs, 1); - } - luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); - luaK_jump(fs); - forbody(ls, base, line, 3, 1); -} - - -static void forlist (LexState *ls, TString *indexname) { - /* forlist -> NAME {,NAME} IN explist1 DO body */ - FuncState *fs = ls->fs; - expdesc e; - int nvars = 0; - int line; - int base = fs->freereg; - new_localvarstr(ls, "(for generator)", nvars++); - new_localvarstr(ls, "(for state)", nvars++); - new_localvar(ls, indexname, nvars++); - while (testnext(ls, ',')) - new_localvar(ls, str_checkname(ls), nvars++); - check(ls, TK_IN); - line = ls->linenumber; - adjust_assign(ls, nvars, explist1(ls, &e), &e); - luaK_checkstack(fs, 3); /* extra space to call generator */ - luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP); - forbody(ls, base, line, nvars, 0); -} - - -static void forstat (LexState *ls, int line) { - /* forstat -> fornum | forlist */ - FuncState *fs = ls->fs; - TString *varname; - BlockCnt bl; - enterblock(fs, &bl, 0); /* block to control variable scope */ - next(ls); /* skip `for' */ - varname = str_checkname(ls); /* first variable name */ - switch (ls->t.token) { - case '=': fornum(ls, varname, line); break; - case ',': case TK_IN: forlist(ls, varname); break; - default: luaX_syntaxerror(ls, "`=' or `in' expected"); - } - check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); -} - - -static void test_then_block (LexState *ls, expdesc *v) { - /* test_then_block -> [IF | ELSEIF] cond THEN block */ - next(ls); /* skip IF or ELSEIF */ - cond(ls, v); - check(ls, TK_THEN); - block(ls); /* `then' part */ -} - - -static void ifstat (LexState *ls, int line) { - /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ - FuncState *fs = ls->fs; - expdesc v; - int escapelist = NO_JUMP; - test_then_block(ls, &v); /* IF cond THEN block */ - while (ls->t.token == TK_ELSEIF) { - luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); - test_then_block(ls, &v); /* ELSEIF cond THEN block */ - } - if (ls->t.token == TK_ELSE) { - luaK_concat(fs, &escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, v.f); - next(ls); /* skip ELSE (after patch, for correct line info) */ - block(ls); /* `else' part */ - } - else - luaK_concat(fs, &escapelist, v.f); - luaK_patchtohere(fs, escapelist); - check_match(ls, TK_END, TK_IF, line); -} - - -static void localfunc (LexState *ls) { - expdesc v, b; - new_localvar(ls, str_checkname(ls), 0); - init_exp(&v, VLOCAL, ls->fs->freereg++); - adjustlocalvars(ls, 1); - body(ls, &b, 0, ls->linenumber); - luaK_storevar(ls->fs, &v, &b); -} - - -static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */ - int nvars = 0; - int nexps; - expdesc e; - do { - new_localvar(ls, str_checkname(ls), nvars++); - } while (testnext(ls, ',')); - if (testnext(ls, '=')) - nexps = explist1(ls, &e); - else { - e.k = VVOID; - nexps = 0; - } - adjust_assign(ls, nvars, nexps, &e); - adjustlocalvars(ls, nvars); -} - - -static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {field} [`:' NAME] */ - int needself = 0; - singlevar(ls, v, 1); - while (ls->t.token == '.') - luaY_field(ls, v); - if (ls->t.token == ':') { - needself = 1; - luaY_field(ls, v); - } - return needself; -} - - -static void funcstat (LexState *ls, int line) { - /* funcstat -> FUNCTION funcname body */ - int needself; - expdesc v, b; - next(ls); /* skip FUNCTION */ - needself = funcname(ls, &v); - body(ls, &b, needself, line); - luaK_storevar(ls->fs, &v, &b); - luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ -} - - -static void exprstat (LexState *ls) { - /* stat -> func | assignment */ - FuncState *fs = ls->fs; - struct LHS_assign v; - primaryexp(ls, &v.v); - if (v.v.k == VCALL) { /* stat -> func */ - luaK_setcallreturns(fs, &v.v, 0); /* call statement uses no results */ - } - else { /* stat -> assignment */ - v.prev = NULL; - assignment(ls, &v, 1); - } -} - - -static void retstat (LexState *ls) { - /* stat -> RETURN explist */ - FuncState *fs = ls->fs; - expdesc e; - int first, nret; /* registers with returned values */ - next(ls); /* skip RETURN */ - if (block_follow(ls->t.token) || ls->t.token == ';') - first = nret = 0; /* return no values */ - else { - nret = explist1(ls, &e); /* optional return values */ - if (e.k == VCALL) { - luaK_setcallreturns(fs, &e, LUA_MULTRET); - if (nret == 1) { /* tail call? */ - SET_OPCODE(getcode(fs,&e), OP_TAILCALL); - lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); - } - first = fs->nactvar; - nret = LUA_MULTRET; /* return all values */ - } - else { - if (nret == 1) /* only one single value? */ - first = luaK_exp2anyreg(fs, &e); - else { - luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ - first = fs->nactvar; /* return all `active' values */ - lua_assert(nret == fs->freereg - first); - } - } - } - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); -} - - -static void breakstat (LexState *ls) { - /* stat -> BREAK [NAME] */ - FuncState *fs = ls->fs; - BlockCnt *bl = fs->bl; - int upval = 0; - next(ls); /* skip BREAK */ - while (bl && !bl->isbreakable) { - upval |= bl->upval; - bl = bl->previous; - } - if (!bl) - luaX_syntaxerror(ls, "no loop to break"); - if (upval) - luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0); - luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); -} - - -static int statement (LexState *ls) { - int line = ls->linenumber; /* may be needed for error messages */ - switch (ls->t.token) { - case TK_IF: { /* stat -> ifstat */ - ifstat(ls, line); - return 0; - } - case TK_WHILE: { /* stat -> whilestat */ - whilestat(ls, line); - return 0; - } - case TK_DO: { /* stat -> DO block END */ - next(ls); /* skip DO */ - block(ls); - check_match(ls, TK_END, TK_DO, line); - return 0; - } - case TK_FOR: { /* stat -> forstat */ - forstat(ls, line); - return 0; - } - case TK_REPEAT: { /* stat -> repeatstat */ - repeatstat(ls, line); - return 0; - } - case TK_FUNCTION: { - funcstat(ls, line); /* stat -> funcstat */ - return 0; - } - case TK_LOCAL: { /* stat -> localstat */ - next(ls); /* skip LOCAL */ - if (testnext(ls, TK_FUNCTION)) /* local function? */ - localfunc(ls); - else - localstat(ls); - return 0; - } - case TK_RETURN: { /* stat -> retstat */ - retstat(ls); - return 1; /* must be last statement */ - } - case TK_BREAK: { /* stat -> breakstat */ - breakstat(ls); - return 1; /* must be last statement */ - } - default: { - exprstat(ls); - return 0; /* to avoid warnings */ - } - } -} - - -static void chunk (LexState *ls) { - /* chunk -> { stat [`;'] } */ - int islast = 0; - enterlevel(ls); - while (!islast && !block_follow(ls->t.token)) { - islast = statement(ls); - testnext(ls, ';'); - lua_assert(ls->fs->freereg >= ls->fs->nactvar); - ls->fs->freereg = ls->fs->nactvar; /* free registers */ - } - leavelevel(ls); -} - -/* }====================================================================== */ +/*
+** $Id: lparser.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Lua Parser
+** See Copyright Notice in lua.h
+*/
+
+
+#include <string.h>
+
+#define lparser_c
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "lfunc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+
+
+
+
+#define getlocvar(fs, i) ((fs)->f->locvars[(fs)->actvar[i]])
+
+
+#define enterlevel(ls) if (++(ls)->nestlevel > LUA_MAXPARSERLEVEL) \
+ luaX_syntaxerror(ls, "too many syntax levels");
+#define leavelevel(ls) ((ls)->nestlevel--)
+
+
+/*
+** nodes for block list (list of active blocks)
+*/
+typedef struct BlockCnt {
+ struct BlockCnt *previous; /* chain */
+ int breaklist; /* list of jumps out of this loop */
+ int nactvar; /* # active local variables outside the breakable structure */
+ int upval; /* true if some variable in the block is an upvalue */
+ int isbreakable; /* true if `block' is a loop */
+} BlockCnt;
+
+
+
+/*
+** prototypes for recursive non-terminal functions
+*/
+static void chunk (LexState *ls);
+static void expr (LexState *ls, expdesc *v);
+
+
+
+static void next (LexState *ls) {
+ ls->lastline = ls->linenumber;
+ if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
+ ls->t = ls->lookahead; /* use this one */
+ ls->lookahead.token = TK_EOS; /* and discharge it */
+ }
+ else
+ ls->t.token = luaX_lex(ls, &ls->t.seminfo); /* read next token */
+}
+
+
+static void lookahead (LexState *ls) {
+ lua_assert(ls->lookahead.token == TK_EOS);
+ ls->lookahead.token = luaX_lex(ls, &ls->lookahead.seminfo);
+}
+
+
+static void error_expected (LexState *ls, int token) {
+ luaX_syntaxerror(ls,
+ luaO_pushfstring(ls->L, "`%s' expected", luaX_token2str(ls, token)));
+}
+
+
+static int testnext (LexState *ls, int c) {
+ if (ls->t.token == c) {
+ next(ls);
+ return 1;
+ }
+ else return 0;
+}
+
+
+static void check (LexState *ls, int c) {
+ if (!testnext(ls, c))
+ error_expected(ls, c);
+}
+
+
+#define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); }
+
+
+
+static void check_match (LexState *ls, int what, int who, int where) {
+ if (!testnext(ls, what)) {
+ if (where == ls->linenumber)
+ error_expected(ls, what);
+ else {
+ luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
+ "`%s' expected (to close `%s' at line %d)",
+ luaX_token2str(ls, what), luaX_token2str(ls, who), where));
+ }
+ }
+}
+
+
+static TString *str_checkname (LexState *ls) {
+ TString *ts;
+ check_condition(ls, (ls->t.token == TK_NAME), "<name> expected");
+ ts = ls->t.seminfo.ts;
+ next(ls);
+ return ts;
+}
+
+
+static void init_exp (expdesc *e, expkind k, int i) {
+ e->f = e->t = NO_JUMP;
+ e->k = k;
+ e->info = i;
+}
+
+
+static void codestring (LexState *ls, expdesc *e, TString *s) {
+ init_exp(e, VK, luaK_stringK(ls->fs, s));
+}
+
+
+static void checkname(LexState *ls, expdesc *e) {
+ codestring(ls, e, str_checkname(ls));
+}
+
+
+static int luaI_registerlocalvar (LexState *ls, TString *varname) {
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
+ LocVar, MAX_INT, "");
+ f->locvars[fs->nlocvars].varname = varname;
+ return fs->nlocvars++;
+}
+
+
+static void new_localvar (LexState *ls, TString *name, int n) {
+ FuncState *fs = ls->fs;
+ luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "local variables");
+ fs->actvar[fs->nactvar+n] = luaI_registerlocalvar(ls, name);
+}
+
+
+static void adjustlocalvars (LexState *ls, int nvars) {
+ FuncState *fs = ls->fs;
+ fs->nactvar += nvars;
+ for (; nvars; nvars--) {
+ getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc;
+ }
+}
+
+
+static void removevars (LexState *ls, int tolevel) {
+ FuncState *fs = ls->fs;
+ while (fs->nactvar > tolevel)
+ getlocvar(fs, --fs->nactvar).endpc = fs->pc;
+}
+
+
+static void new_localvarstr (LexState *ls, const char *name, int n) {
+ new_localvar(ls, luaS_new(ls->L, name), n);
+}
+
+
+static void create_local (LexState *ls, const char *name) {
+ new_localvarstr(ls, name, 0);
+ adjustlocalvars(ls, 1);
+}
+
+
+static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
+ int i;
+ Proto *f = fs->f;
+ for (i=0; i<f->nups; i++) {
+ if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->info) {
+ lua_assert(fs->f->upvalues[i] == name);
+ return i;
+ }
+ }
+ /* new one */
+ luaX_checklimit(fs->ls, f->nups + 1, MAXUPVALUES, "upvalues");
+ luaM_growvector(fs->L, fs->f->upvalues, f->nups, fs->f->sizeupvalues,
+ TString *, MAX_INT, "");
+ fs->f->upvalues[f->nups] = name;
+ fs->upvalues[f->nups] = *v;
+ return f->nups++;
+}
+
+
+static int searchvar (FuncState *fs, TString *n) {
+ int i;
+ for (i=fs->nactvar-1; i >= 0; i--) {
+ if (n == getlocvar(fs, i).varname)
+ return i;
+ }
+ return -1; /* not found */
+}
+
+
+static void markupval (FuncState *fs, int level) {
+ BlockCnt *bl = fs->bl;
+ while (bl && bl->nactvar > level) bl = bl->previous;
+ if (bl) bl->upval = 1;
+}
+
+
+static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
+ if (fs == NULL) /* no more levels? */
+ init_exp(var, VGLOBAL, NO_REG); /* default is global variable */
+ else {
+ int v = searchvar(fs, n); /* look up at current level */
+ if (v >= 0) {
+ init_exp(var, VLOCAL, v);
+ if (!base)
+ markupval(fs, v); /* local will be used as an upval */
+ }
+ else { /* not found at current level; try upper one */
+ singlevaraux(fs->prev, n, var, 0);
+ if (var->k == VGLOBAL) {
+ if (base)
+ var->info = luaK_stringK(fs, n); /* info points to global name */
+ }
+ else { /* LOCAL or UPVAL */
+ var->info = indexupvalue(fs, n, var);
+ var->k = VUPVAL; /* upvalue in this level */
+ }
+ }
+ }
+}
+
+
+static TString *singlevar (LexState *ls, expdesc *var, int base) {
+ TString *varname = str_checkname(ls);
+ singlevaraux(ls->fs, varname, var, base);
+ return varname;
+}
+
+
+static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
+ FuncState *fs = ls->fs;
+ int extra = nvars - nexps;
+ if (e->k == VCALL) {
+ extra++; /* includes call itself */
+ if (extra <= 0) extra = 0;
+ else luaK_reserveregs(fs, extra-1);
+ luaK_setcallreturns(fs, e, extra); /* call provides the difference */
+ }
+ else {
+ if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */
+ if (extra > 0) {
+ int reg = fs->freereg;
+ luaK_reserveregs(fs, extra);
+ luaK_nil(fs, reg, extra);
+ }
+ }
+}
+
+
+static void code_params (LexState *ls, int nparams, int dots) {
+ FuncState *fs = ls->fs;
+ adjustlocalvars(ls, nparams);
+ luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters");
+ fs->f->numparams = cast(lu_byte, fs->nactvar);
+ fs->f->is_vararg = cast(lu_byte, dots);
+ if (dots)
+ create_local(ls, "arg");
+ luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */
+}
+
+
+static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) {
+ bl->breaklist = NO_JUMP;
+ bl->isbreakable = isbreakable;
+ bl->nactvar = fs->nactvar;
+ bl->upval = 0;
+ bl->previous = fs->bl;
+ fs->bl = bl;
+ lua_assert(fs->freereg == fs->nactvar);
+}
+
+
+static void leaveblock (FuncState *fs) {
+ BlockCnt *bl = fs->bl;
+ fs->bl = bl->previous;
+ removevars(fs->ls, bl->nactvar);
+ if (bl->upval)
+ luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
+ lua_assert(bl->nactvar == fs->nactvar);
+ fs->freereg = fs->nactvar; /* free registers */
+ luaK_patchtohere(fs, bl->breaklist);
+}
+
+
+static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ int i;
+ luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
+ MAXARG_Bx, "constant table overflow");
+ f->p[fs->np++] = func->f;
+ init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
+ for (i=0; i<func->f->nups; i++) {
+ OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
+ luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0);
+ }
+}
+
+
+static void open_func (LexState *ls, FuncState *fs) {
+ Proto *f = luaF_newproto(ls->L);
+ fs->f = f;
+ fs->prev = ls->fs; /* linked list of funcstates */
+ fs->ls = ls;
+ fs->L = ls->L;
+ ls->fs = fs;
+ fs->pc = 0;
+ fs->lasttarget = 0;
+ fs->jpc = NO_JUMP;
+ fs->freereg = 0;
+ fs->nk = 0;
+ fs->h = luaH_new(ls->L, 0, 0);
+ fs->np = 0;
+ fs->nlocvars = 0;
+ fs->nactvar = 0;
+ fs->bl = NULL;
+ f->source = ls->source;
+ f->maxstacksize = 2; /* registers 0/1 are always valid */
+}
+
+
+static void close_func (LexState *ls) {
+ lua_State *L = ls->L;
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f;
+ removevars(ls, 0);
+ luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */
+ luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
+ f->sizecode = fs->pc;
+ luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
+ f->sizelineinfo = fs->pc;
+ luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject);
+ f->sizek = fs->nk;
+ luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
+ f->sizep = fs->np;
+ luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
+ f->sizelocvars = fs->nlocvars;
+ luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *);
+ f->sizeupvalues = f->nups;
+ lua_assert(luaG_checkcode(f));
+ lua_assert(fs->bl == NULL);
+ ls->fs = fs->prev;
+}
+
+
+Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff) {
+ struct LexState lexstate;
+ struct FuncState funcstate;
+ lexstate.buff = buff;
+ lexstate.nestlevel = 0;
+ luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z)));
+ open_func(&lexstate, &funcstate);
+ next(&lexstate); /* read first token */
+ chunk(&lexstate);
+ check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected");
+ close_func(&lexstate);
+ lua_assert(funcstate.prev == NULL);
+ lua_assert(funcstate.f->nups == 0);
+ lua_assert(lexstate.nestlevel == 0);
+ return funcstate.f;
+}
+
+
+
+/*============================================================*/
+/* GRAMMAR RULES */
+/*============================================================*/
+
+
+static void luaY_field (LexState *ls, expdesc *v) {
+ /* field -> ['.' | ':'] NAME */
+ FuncState *fs = ls->fs;
+ expdesc key;
+ luaK_exp2anyreg(fs, v);
+ next(ls); /* skip the dot or colon */
+ checkname(ls, &key);
+ luaK_indexed(fs, v, &key);
+}
+
+
+static void luaY_index (LexState *ls, expdesc *v) {
+ /* index -> '[' expr ']' */
+ next(ls); /* skip the '[' */
+ expr(ls, v);
+ luaK_exp2val(ls->fs, v);
+ check(ls, ']');
+}
+
+
+/*
+** {======================================================================
+** Rules for Constructors
+** =======================================================================
+*/
+
+
+struct ConsControl {
+ expdesc v; /* last list item read */
+ expdesc *t; /* table descriptor */
+ int nh; /* total number of `record' elements */
+ int na; /* total number of array elements */
+ int tostore; /* number of array elements pending to be stored */
+};
+
+
+static void recfield (LexState *ls, struct ConsControl *cc) {
+ /* recfield -> (NAME | `['exp1`]') = exp1 */
+ FuncState *fs = ls->fs;
+ int reg = ls->fs->freereg;
+ expdesc key, val;
+ if (ls->t.token == TK_NAME) {
+ luaX_checklimit(ls, cc->nh, MAX_INT, "items in a constructor");
+ cc->nh++;
+ checkname(ls, &key);
+ }
+ else /* ls->t.token == '[' */
+ luaY_index(ls, &key);
+ check(ls, '=');
+ luaK_exp2RK(fs, &key);
+ expr(ls, &val);
+ luaK_codeABC(fs, OP_SETTABLE, cc->t->info, luaK_exp2RK(fs, &key),
+ luaK_exp2RK(fs, &val));
+ fs->freereg = reg; /* free registers */
+}
+
+
+static void closelistfield (FuncState *fs, struct ConsControl *cc) {
+ if (cc->v.k == VVOID) return; /* there is no list item */
+ luaK_exp2nextreg(fs, &cc->v);
+ cc->v.k = VVOID;
+ if (cc->tostore == LFIELDS_PER_FLUSH) {
+ luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1); /* flush */
+ cc->tostore = 0; /* no more items pending */
+ fs->freereg = cc->t->info + 1; /* free registers */
+ }
+}
+
+
+static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
+ if (cc->tostore == 0) return;
+ if (cc->v.k == VCALL) {
+ luaK_setcallreturns(fs, &cc->v, LUA_MULTRET);
+ luaK_codeABx(fs, OP_SETLISTO, cc->t->info, cc->na-1);
+ }
+ else {
+ if (cc->v.k != VVOID)
+ luaK_exp2nextreg(fs, &cc->v);
+ luaK_codeABx(fs, OP_SETLIST, cc->t->info, cc->na-1);
+ }
+ fs->freereg = cc->t->info + 1; /* free registers */
+}
+
+
+static void listfield (LexState *ls, struct ConsControl *cc) {
+ expr(ls, &cc->v);
+ luaX_checklimit(ls, cc->na, MAXARG_Bx, "items in a constructor");
+ cc->na++;
+ cc->tostore++;
+}
+
+
+static void constructor (LexState *ls, expdesc *t) {
+ /* constructor -> ?? */
+ FuncState *fs = ls->fs;
+ int line = ls->linenumber;
+ int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
+ struct ConsControl cc;
+ cc.na = cc.nh = cc.tostore = 0;
+ cc.t = t;
+ init_exp(t, VRELOCABLE, pc);
+ init_exp(&cc.v, VVOID, 0); /* no value (yet) */
+ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top (for gc) */
+ check(ls, '{');
+ do {
+ lua_assert(cc.v.k == VVOID || cc.tostore > 0);
+ testnext(ls, ';'); /* compatibility only */
+ if (ls->t.token == '}') break;
+ closelistfield(fs, &cc);
+ switch(ls->t.token) {
+ case TK_NAME: { /* may be listfields or recfields */
+ lookahead(ls);
+ if (ls->lookahead.token != '=') /* expression? */
+ listfield(ls, &cc);
+ else
+ recfield(ls, &cc);
+ break;
+ }
+ case '[': { /* constructor_item -> recfield */
+ recfield(ls, &cc);
+ break;
+ }
+ default: { /* constructor_part -> listfield */
+ listfield(ls, &cc);
+ break;
+ }
+ }
+ } while (testnext(ls, ',') || testnext(ls, ';'));
+ check_match(ls, '}', '{', line);
+ lastlistfield(fs, &cc);
+ SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
+ SETARG_C(fs->f->code[pc], luaO_log2(cc.nh)+1); /* set initial table size */
+}
+
+/* }====================================================================== */
+
+
+
+static void parlist (LexState *ls) {
+ /* parlist -> [ param { `,' param } ] */
+ int nparams = 0;
+ int dots = 0;
+ if (ls->t.token != ')') { /* is `parlist' not empty? */
+ do {
+ switch (ls->t.token) {
+ case TK_DOTS: dots = 1; next(ls); break;
+ case TK_NAME: new_localvar(ls, str_checkname(ls), nparams++); break;
+ default: luaX_syntaxerror(ls, "<name> or `...' expected");
+ }
+ } while (!dots && testnext(ls, ','));
+ }
+ code_params(ls, nparams, dots);
+}
+
+
+static void body (LexState *ls, expdesc *e, int needself, int line) {
+ /* body -> `(' parlist `)' chunk END */
+ FuncState new_fs;
+ open_func(ls, &new_fs);
+ new_fs.f->lineDefined = line;
+ check(ls, '(');
+ if (needself)
+ create_local(ls, "self");
+ parlist(ls);
+ check(ls, ')');
+ chunk(ls);
+ check_match(ls, TK_END, TK_FUNCTION, line);
+ close_func(ls);
+ pushclosure(ls, &new_fs, e);
+}
+
+
+static int explist1 (LexState *ls, expdesc *v) {
+ /* explist1 -> expr { `,' expr } */
+ int n = 1; /* at least one expression */
+ expr(ls, v);
+ while (testnext(ls, ',')) {
+ luaK_exp2nextreg(ls->fs, v);
+ expr(ls, v);
+ n++;
+ }
+ return n;
+}
+
+
+static void funcargs (LexState *ls, expdesc *f) {
+ FuncState *fs = ls->fs;
+ expdesc args;
+ int base, nparams;
+ int line = ls->linenumber;
+ switch (ls->t.token) {
+ case '(': { /* funcargs -> `(' [ explist1 ] `)' */
+ if (line != ls->lastline)
+ luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
+ next(ls);
+ if (ls->t.token == ')') /* arg list is empty? */
+ args.k = VVOID;
+ else {
+ explist1(ls, &args);
+ luaK_setcallreturns(fs, &args, LUA_MULTRET);
+ }
+ check_match(ls, ')', '(', line);
+ break;
+ }
+ case '{': { /* funcargs -> constructor */
+ constructor(ls, &args);
+ break;
+ }
+ case TK_STRING: { /* funcargs -> STRING */
+ codestring(ls, &args, ls->t.seminfo.ts);
+ next(ls); /* must use `seminfo' before `next' */
+ break;
+ }
+ default: {
+ luaX_syntaxerror(ls, "function arguments expected");
+ return;
+ }
+ }
+ lua_assert(f->k == VNONRELOC);
+ base = f->info; /* base register for call */
+ if (args.k == VCALL)
+ nparams = LUA_MULTRET; /* open call */
+ else {
+ if (args.k != VVOID)
+ luaK_exp2nextreg(fs, &args); /* close last argument */
+ nparams = fs->freereg - (base+1);
+ }
+ init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
+ luaK_fixline(fs, line);
+ fs->freereg = base+1; /* call remove function and arguments and leaves
+ (unless changed) one result */
+}
+
+
+
+
+/*
+** {======================================================================
+** Expression parsing
+** =======================================================================
+*/
+
+
+static void prefixexp (LexState *ls, expdesc *v) {
+ /* prefixexp -> NAME | '(' expr ')' */
+ switch (ls->t.token) {
+ case '(': {
+ int line = ls->linenumber;
+ next(ls);
+ expr(ls, v);
+ check_match(ls, ')', '(', line);
+ luaK_dischargevars(ls->fs, v);
+ return;
+ }
+ case TK_NAME: {
+ singlevar(ls, v, 1);
+ return;
+ }
+#ifdef LUA_COMPATUPSYNTAX
+ case '%': { /* for compatibility only */
+ TString *varname;
+ int line = ls->linenumber;
+ next(ls); /* skip `%' */
+ varname = singlevar(ls, v, 1);
+ if (v->k != VUPVAL)
+ luaX_errorline(ls, "global upvalues are obsolete",
+ getstr(varname), line);
+ return;
+ }
+#endif
+ default: {
+ luaX_syntaxerror(ls, "unexpected symbol");
+ return;
+ }
+ }
+}
+
+
+static void primaryexp (LexState *ls, expdesc *v) {
+ /* primaryexp ->
+ prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
+ FuncState *fs = ls->fs;
+ prefixexp(ls, v);
+ for (;;) {
+ switch (ls->t.token) {
+ case '.': { /* field */
+ luaY_field(ls, v);
+ break;
+ }
+ case '[': { /* `[' exp1 `]' */
+ expdesc key;
+ luaK_exp2anyreg(fs, v);
+ luaY_index(ls, &key);
+ luaK_indexed(fs, v, &key);
+ break;
+ }
+ case ':': { /* `:' NAME funcargs */
+ expdesc key;
+ next(ls);
+ checkname(ls, &key);
+ luaK_self(fs, v, &key);
+ funcargs(ls, v);
+ break;
+ }
+ case '(': case TK_STRING: case '{': { /* funcargs */
+ luaK_exp2nextreg(fs, v);
+ funcargs(ls, v);
+ break;
+ }
+ default: return;
+ }
+ }
+}
+
+
+static void simpleexp (LexState *ls, expdesc *v) {
+ /* simpleexp -> NUMBER | STRING | NIL | constructor | FUNCTION body
+ | primaryexp */
+ switch (ls->t.token) {
+ case TK_NUMBER: {
+ init_exp(v, VK, luaK_numberK(ls->fs, ls->t.seminfo.r));
+ next(ls); /* must use `seminfo' before `next' */
+ break;
+ }
+ case TK_STRING: {
+ codestring(ls, v, ls->t.seminfo.ts);
+ next(ls); /* must use `seminfo' before `next' */
+ break;
+ }
+ case TK_NIL: {
+ init_exp(v, VNIL, 0);
+ next(ls);
+ break;
+ }
+ case TK_TRUE: {
+ init_exp(v, VTRUE, 0);
+ next(ls);
+ break;
+ }
+ case TK_FALSE: {
+ init_exp(v, VFALSE, 0);
+ next(ls);
+ break;
+ }
+ case '{': { /* constructor */
+ constructor(ls, v);
+ break;
+ }
+ case TK_FUNCTION: {
+ next(ls);
+ body(ls, v, 0, ls->linenumber);
+ break;
+ }
+ default: {
+ primaryexp(ls, v);
+ break;
+ }
+ }
+}
+
+
+static UnOpr getunopr (int op) {
+ switch (op) {
+ case TK_NOT: return OPR_NOT;
+ case '-': return OPR_MINUS;
+ default: return OPR_NOUNOPR;
+ }
+}
+
+
+static BinOpr getbinopr (int op) {
+ switch (op) {
+ case '+': return OPR_ADD;
+ case '-': return OPR_SUB;
+ case '*': return OPR_MULT;
+ case '/': return OPR_DIV;
+ case '^': return OPR_POW;
+ case TK_CONCAT: return OPR_CONCAT;
+ case TK_NE: return OPR_NE;
+ case TK_EQ: return OPR_EQ;
+ case '<': return OPR_LT;
+ case TK_LE: return OPR_LE;
+ case '>': return OPR_GT;
+ case TK_GE: return OPR_GE;
+ case TK_AND: return OPR_AND;
+ case TK_OR: return OPR_OR;
+ default: return OPR_NOBINOPR;
+ }
+}
+
+
+static const struct {
+ lu_byte left; /* left priority for each binary operator */
+ lu_byte right; /* right priority */
+} priority[] = { /* ORDER OPR */
+ {6, 6}, {6, 6}, {7, 7}, {7, 7}, /* arithmetic */
+ {10, 9}, {5, 4}, /* power and concat (right associative) */
+ {3, 3}, {3, 3}, /* equality */
+ {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */
+ {2, 2}, {1, 1} /* logical (and/or) */
+};
+
+#define UNARY_PRIORITY 8 /* priority for unary operators */
+
+
+/*
+** subexpr -> (simplexep | unop subexpr) { binop subexpr }
+** where `binop' is any binary operator with a priority higher than `limit'
+*/
+static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
+ BinOpr op;
+ UnOpr uop;
+ enterlevel(ls);
+ uop = getunopr(ls->t.token);
+ if (uop != OPR_NOUNOPR) {
+ next(ls);
+ subexpr(ls, v, UNARY_PRIORITY);
+ luaK_prefix(ls->fs, uop, v);
+ }
+ else simpleexp(ls, v);
+ /* expand while operators have priorities higher than `limit' */
+ op = getbinopr(ls->t.token);
+ while (op != OPR_NOBINOPR && cast(int, priority[op].left) > limit) {
+ expdesc v2;
+ BinOpr nextop;
+ next(ls);
+ luaK_infix(ls->fs, op, v);
+ /* read sub-expression with higher priority */
+ nextop = subexpr(ls, &v2, cast(int, priority[op].right));
+ luaK_posfix(ls->fs, op, v, &v2);
+ op = nextop;
+ }
+ leavelevel(ls);
+ return op; /* return first untreated operator */
+}
+
+
+static void expr (LexState *ls, expdesc *v) {
+ subexpr(ls, v, -1);
+}
+
+/* }==================================================================== */
+
+
+
+/*
+** {======================================================================
+** Rules for Statements
+** =======================================================================
+*/
+
+
+static int block_follow (int token) {
+ switch (token) {
+ case TK_ELSE: case TK_ELSEIF: case TK_END:
+ case TK_UNTIL: case TK_EOS:
+ return 1;
+ default: return 0;
+ }
+}
+
+
+static void block (LexState *ls) {
+ /* block -> chunk */
+ FuncState *fs = ls->fs;
+ BlockCnt bl;
+ enterblock(fs, &bl, 0);
+ chunk(ls);
+ lua_assert(bl.breaklist == NO_JUMP);
+ leaveblock(fs);
+}
+
+
+/*
+** structure to chain all variables in the left-hand side of an
+** assignment
+*/
+struct LHS_assign {
+ struct LHS_assign *prev;
+ expdesc v; /* variable (global, local, upvalue, or indexed) */
+};
+
+
+/*
+** check whether, in an assignment to a local variable, the local variable
+** is needed in a previous assignment (to a table). If so, save original
+** local value in a safe place and use this safe copy in the previous
+** assignment.
+*/
+static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
+ FuncState *fs = ls->fs;
+ int extra = fs->freereg; /* eventual position to save local variable */
+ int conflict = 0;
+ for (; lh; lh = lh->prev) {
+ if (lh->v.k == VINDEXED) {
+ if (lh->v.info == v->info) { /* conflict? */
+ conflict = 1;
+ lh->v.info = extra; /* previous assignment will use safe copy */
+ }
+ if (lh->v.aux == v->info) { /* conflict? */
+ conflict = 1;
+ lh->v.aux = extra; /* previous assignment will use safe copy */
+ }
+ }
+ }
+ if (conflict) {
+ luaK_codeABC(fs, OP_MOVE, fs->freereg, v->info, 0); /* make copy */
+ luaK_reserveregs(fs, 1);
+ }
+}
+
+
+static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
+ expdesc e;
+ check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
+ "syntax error");
+ if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */
+ struct LHS_assign nv;
+ nv.prev = lh;
+ primaryexp(ls, &nv.v);
+ if (nv.v.k == VLOCAL)
+ check_conflict(ls, lh, &nv.v);
+ assignment(ls, &nv, nvars+1);
+ }
+ else { /* assignment -> `=' explist1 */
+ int nexps;
+ check(ls, '=');
+ nexps = explist1(ls, &e);
+ if (nexps != nvars) {
+ adjust_assign(ls, nvars, nexps, &e);
+ if (nexps > nvars)
+ ls->fs->freereg -= nexps - nvars; /* remove extra values */
+ }
+ else {
+ luaK_setcallreturns(ls->fs, &e, 1); /* close last expression */
+ luaK_storevar(ls->fs, &lh->v, &e);
+ return; /* avoid default */
+ }
+ }
+ init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */
+ luaK_storevar(ls->fs, &lh->v, &e);
+}
+
+
+static void cond (LexState *ls, expdesc *v) {
+ /* cond -> exp */
+ expr(ls, v); /* read condition */
+ if (v->k == VNIL) v->k = VFALSE; /* `falses' are all equal here */
+ luaK_goiftrue(ls->fs, v);
+ luaK_patchtohere(ls->fs, v->t);
+}
+
+
+/*
+** The while statement optimizes its code by coding the condition
+** after its body (and thus avoiding one jump in the loop).
+*/
+
+/*
+** maximum size of expressions for optimizing `while' code
+*/
+#ifndef MAXEXPWHILE
+#define MAXEXPWHILE 100
+#endif
+
+/*
+** the call `luaK_goiffalse' may grow the size of an expression by
+** at most this:
+*/
+#define EXTRAEXP 5
+
+static void whilestat (LexState *ls, int line) {
+ /* whilestat -> WHILE cond DO block END */
+ Instruction codeexp[MAXEXPWHILE + EXTRAEXP];
+ int lineexp;
+ int i;
+ int sizeexp;
+ FuncState *fs = ls->fs;
+ int whileinit, blockinit, expinit;
+ expdesc v;
+ BlockCnt bl;
+ next(ls); /* skip WHILE */
+ whileinit = luaK_jump(fs); /* jump to condition (which will be moved) */
+ expinit = luaK_getlabel(fs);
+ expr(ls, &v); /* parse condition */
+ if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */
+ lineexp = ls->linenumber;
+ luaK_goiffalse(fs, &v);
+ luaK_concat(fs, &v.f, fs->jpc);
+ fs->jpc = NO_JUMP;
+ sizeexp = fs->pc - expinit; /* size of expression code */
+ if (sizeexp > MAXEXPWHILE)
+ luaX_syntaxerror(ls, "`while' condition too complex");
+ for (i = 0; i < sizeexp; i++) /* save `exp' code */
+ codeexp[i] = fs->f->code[expinit + i];
+ fs->pc = expinit; /* remove `exp' code */
+ enterblock(fs, &bl, 1);
+ check(ls, TK_DO);
+ blockinit = luaK_getlabel(fs);
+ block(ls);
+ luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */
+ /* move `exp' back to code */
+ if (v.t != NO_JUMP) v.t += fs->pc - expinit;
+ if (v.f != NO_JUMP) v.f += fs->pc - expinit;
+ for (i=0; i<sizeexp; i++)
+ luaK_code(fs, codeexp[i], lineexp);
+ check_match(ls, TK_END, TK_WHILE, line);
+ leaveblock(fs);
+ luaK_patchlist(fs, v.t, blockinit); /* true conditions go back to loop */
+ luaK_patchtohere(fs, v.f); /* false conditions finish the loop */
+}
+
+
+static void repeatstat (LexState *ls, int line) {
+ /* repeatstat -> REPEAT block UNTIL cond */
+ FuncState *fs = ls->fs;
+ int repeat_init = luaK_getlabel(fs);
+ expdesc v;
+ BlockCnt bl;
+ enterblock(fs, &bl, 1);
+ next(ls);
+ block(ls);
+ check_match(ls, TK_UNTIL, TK_REPEAT, line);
+ cond(ls, &v);
+ luaK_patchlist(fs, v.f, repeat_init);
+ leaveblock(fs);
+}
+
+
+static int exp1 (LexState *ls) {
+ expdesc e;
+ int k;
+ expr(ls, &e);
+ k = e.k;
+ luaK_exp2nextreg(ls->fs, &e);
+ return k;
+}
+
+
+static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
+ BlockCnt bl;
+ FuncState *fs = ls->fs;
+ int prep, endfor;
+ adjustlocalvars(ls, nvars); /* scope for all variables */
+ check(ls, TK_DO);
+ enterblock(fs, &bl, 1); /* loop block */
+ prep = luaK_getlabel(fs);
+ block(ls);
+ luaK_patchtohere(fs, prep-1);
+ endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
+ luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3);
+ luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */
+ luaK_patchlist(fs, (isnum) ? endfor : luaK_jump(fs), prep);
+ leaveblock(fs);
+}
+
+
+static void fornum (LexState *ls, TString *varname, int line) {
+ /* fornum -> NAME = exp1,exp1[,exp1] DO body */
+ FuncState *fs = ls->fs;
+ int base = fs->freereg;
+ new_localvar(ls, varname, 0);
+ new_localvarstr(ls, "(for limit)", 1);
+ new_localvarstr(ls, "(for step)", 2);
+ check(ls, '=');
+ exp1(ls); /* initial value */
+ check(ls, ',');
+ exp1(ls); /* limit */
+ if (testnext(ls, ','))
+ exp1(ls); /* optional step */
+ else { /* default step = 1 */
+ luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
+ luaK_reserveregs(fs, 1);
+ }
+ luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1);
+ luaK_jump(fs);
+ forbody(ls, base, line, 3, 1);
+}
+
+
+static void forlist (LexState *ls, TString *indexname) {
+ /* forlist -> NAME {,NAME} IN explist1 DO body */
+ FuncState *fs = ls->fs;
+ expdesc e;
+ int nvars = 0;
+ int line;
+ int base = fs->freereg;
+ new_localvarstr(ls, "(for generator)", nvars++);
+ new_localvarstr(ls, "(for state)", nvars++);
+ new_localvar(ls, indexname, nvars++);
+ while (testnext(ls, ','))
+ new_localvar(ls, str_checkname(ls), nvars++);
+ check(ls, TK_IN);
+ line = ls->linenumber;
+ adjust_assign(ls, nvars, explist1(ls, &e), &e);
+ luaK_checkstack(fs, 3); /* extra space to call generator */
+ luaK_codeAsBx(fs, OP_TFORPREP, base, NO_JUMP);
+ forbody(ls, base, line, nvars, 0);
+}
+
+
+static void forstat (LexState *ls, int line) {
+ /* forstat -> fornum | forlist */
+ FuncState *fs = ls->fs;
+ TString *varname;
+ BlockCnt bl;
+ enterblock(fs, &bl, 0); /* block to control variable scope */
+ next(ls); /* skip `for' */
+ varname = str_checkname(ls); /* first variable name */
+ switch (ls->t.token) {
+ case '=': fornum(ls, varname, line); break;
+ case ',': case TK_IN: forlist(ls, varname); break;
+ default: luaX_syntaxerror(ls, "`=' or `in' expected");
+ }
+ check_match(ls, TK_END, TK_FOR, line);
+ leaveblock(fs);
+}
+
+
+static void test_then_block (LexState *ls, expdesc *v) {
+ /* test_then_block -> [IF | ELSEIF] cond THEN block */
+ next(ls); /* skip IF or ELSEIF */
+ cond(ls, v);
+ check(ls, TK_THEN);
+ block(ls); /* `then' part */
+}
+
+
+static void ifstat (LexState *ls, int line) {
+ /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
+ FuncState *fs = ls->fs;
+ expdesc v;
+ int escapelist = NO_JUMP;
+ test_then_block(ls, &v); /* IF cond THEN block */
+ while (ls->t.token == TK_ELSEIF) {
+ luaK_concat(fs, &escapelist, luaK_jump(fs));
+ luaK_patchtohere(fs, v.f);
+ test_then_block(ls, &v); /* ELSEIF cond THEN block */
+ }
+ if (ls->t.token == TK_ELSE) {
+ luaK_concat(fs, &escapelist, luaK_jump(fs));
+ luaK_patchtohere(fs, v.f);
+ next(ls); /* skip ELSE (after patch, for correct line info) */
+ block(ls); /* `else' part */
+ }
+ else
+ luaK_concat(fs, &escapelist, v.f);
+ luaK_patchtohere(fs, escapelist);
+ check_match(ls, TK_END, TK_IF, line);
+}
+
+
+static void localfunc (LexState *ls) {
+ expdesc v, b;
+ new_localvar(ls, str_checkname(ls), 0);
+ init_exp(&v, VLOCAL, ls->fs->freereg++);
+ adjustlocalvars(ls, 1);
+ body(ls, &b, 0, ls->linenumber);
+ luaK_storevar(ls->fs, &v, &b);
+}
+
+
+static void localstat (LexState *ls) {
+ /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
+ int nvars = 0;
+ int nexps;
+ expdesc e;
+ do {
+ new_localvar(ls, str_checkname(ls), nvars++);
+ } while (testnext(ls, ','));
+ if (testnext(ls, '='))
+ nexps = explist1(ls, &e);
+ else {
+ e.k = VVOID;
+ nexps = 0;
+ }
+ adjust_assign(ls, nvars, nexps, &e);
+ adjustlocalvars(ls, nvars);
+}
+
+
+static int funcname (LexState *ls, expdesc *v) {
+ /* funcname -> NAME {field} [`:' NAME] */
+ int needself = 0;
+ singlevar(ls, v, 1);
+ while (ls->t.token == '.')
+ luaY_field(ls, v);
+ if (ls->t.token == ':') {
+ needself = 1;
+ luaY_field(ls, v);
+ }
+ return needself;
+}
+
+
+static void funcstat (LexState *ls, int line) {
+ /* funcstat -> FUNCTION funcname body */
+ int needself;
+ expdesc v, b;
+ next(ls); /* skip FUNCTION */
+ needself = funcname(ls, &v);
+ body(ls, &b, needself, line);
+ luaK_storevar(ls->fs, &v, &b);
+ luaK_fixline(ls->fs, line); /* definition `happens' in the first line */
+}
+
+
+static void exprstat (LexState *ls) {
+ /* stat -> func | assignment */
+ FuncState *fs = ls->fs;
+ struct LHS_assign v;
+ primaryexp(ls, &v.v);
+ if (v.v.k == VCALL) { /* stat -> func */
+ luaK_setcallreturns(fs, &v.v, 0); /* call statement uses no results */
+ }
+ else { /* stat -> assignment */
+ v.prev = NULL;
+ assignment(ls, &v, 1);
+ }
+}
+
+
+static void retstat (LexState *ls) {
+ /* stat -> RETURN explist */
+ FuncState *fs = ls->fs;
+ expdesc e;
+ int first, nret; /* registers with returned values */
+ next(ls); /* skip RETURN */
+ if (block_follow(ls->t.token) || ls->t.token == ';')
+ first = nret = 0; /* return no values */
+ else {
+ nret = explist1(ls, &e); /* optional return values */
+ if (e.k == VCALL) {
+ luaK_setcallreturns(fs, &e, LUA_MULTRET);
+ if (nret == 1) { /* tail call? */
+ SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
+ lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
+ }
+ first = fs->nactvar;
+ nret = LUA_MULTRET; /* return all values */
+ }
+ else {
+ if (nret == 1) /* only one single value? */
+ first = luaK_exp2anyreg(fs, &e);
+ else {
+ luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */
+ first = fs->nactvar; /* return all `active' values */
+ lua_assert(nret == fs->freereg - first);
+ }
+ }
+ }
+ luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
+}
+
+
+static void breakstat (LexState *ls) {
+ /* stat -> BREAK [NAME] */
+ FuncState *fs = ls->fs;
+ BlockCnt *bl = fs->bl;
+ int upval = 0;
+ next(ls); /* skip BREAK */
+ while (bl && !bl->isbreakable) {
+ upval |= bl->upval;
+ bl = bl->previous;
+ }
+ if (!bl)
+ luaX_syntaxerror(ls, "no loop to break");
+ if (upval)
+ luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
+ luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
+}
+
+
+static int statement (LexState *ls) {
+ int line = ls->linenumber; /* may be needed for error messages */
+ switch (ls->t.token) {
+ case TK_IF: { /* stat -> ifstat */
+ ifstat(ls, line);
+ return 0;
+ }
+ case TK_WHILE: { /* stat -> whilestat */
+ whilestat(ls, line);
+ return 0;
+ }
+ case TK_DO: { /* stat -> DO block END */
+ next(ls); /* skip DO */
+ block(ls);
+ check_match(ls, TK_END, TK_DO, line);
+ return 0;
+ }
+ case TK_FOR: { /* stat -> forstat */
+ forstat(ls, line);
+ return 0;
+ }
+ case TK_REPEAT: { /* stat -> repeatstat */
+ repeatstat(ls, line);
+ return 0;
+ }
+ case TK_FUNCTION: {
+ funcstat(ls, line); /* stat -> funcstat */
+ return 0;
+ }
+ case TK_LOCAL: { /* stat -> localstat */
+ next(ls); /* skip LOCAL */
+ if (testnext(ls, TK_FUNCTION)) /* local function? */
+ localfunc(ls);
+ else
+ localstat(ls);
+ return 0;
+ }
+ case TK_RETURN: { /* stat -> retstat */
+ retstat(ls);
+ return 1; /* must be last statement */
+ }
+ case TK_BREAK: { /* stat -> breakstat */
+ breakstat(ls);
+ return 1; /* must be last statement */
+ }
+ default: {
+ exprstat(ls);
+ return 0; /* to avoid warnings */
+ }
+ }
+}
+
+
+static void chunk (LexState *ls) {
+ /* chunk -> { stat [`;'] } */
+ int islast = 0;
+ enterlevel(ls);
+ while (!islast && !block_follow(ls->t.token)) {
+ islast = statement(ls);
+ testnext(ls, ';');
+ lua_assert(ls->fs->freereg >= ls->fs->nactvar);
+ ls->fs->freereg = ls->fs->nactvar; /* free registers */
+ }
+ leavelevel(ls);
+}
+
+/* }====================================================================== */
diff --git a/lib/lua/src/lstate.c b/lib/lua/src/lstate.c index f6dd14f..53eb6aa 100644 --- a/lib/lua/src/lstate.c +++ b/lib/lua/src/lstate.c @@ -1,220 +1,220 @@ -/* -** $Id: lstate.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Global State -** See Copyright Notice in lua.h -*/ - - -#include <stdlib.h> - -#define lstate_c - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "llex.h" -#include "lmem.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" - - -/* -** macro to allow the inclusion of user information in Lua state -*/ -#ifndef LUA_USERSTATE -#define EXTRASPACE 0 -#else -union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; -#define EXTRASPACE (sizeof(union UEXTRASPACE)) -#endif - - - -/* -** you can change this function through the official API: -** call `lua_setpanicf' -*/ -static int default_panic (lua_State *L) { - UNUSED(L); - return 0; -} - - -static lua_State *mallocstate (lua_State *L) { - lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE); - if (block == NULL) return NULL; - else { - block += EXTRASPACE; - return cast(lua_State *, block); - } -} - - -static void freestate (lua_State *L, lua_State *L1) { - luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE, - sizeof(lua_State) + EXTRASPACE); -} - - -static void stack_init (lua_State *L1, lua_State *L) { - L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject); - L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; - L1->top = L1->stack; - L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; - L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); - L1->ci = L1->base_ci; - L1->ci->state = CI_C; /* not a Lua function */ - setnilvalue(L1->top++); /* `function' entry for this `ci' */ - L1->base = L1->ci->base = L1->top; - L1->ci->top = L1->top + LUA_MINSTACK; - L1->size_ci = BASIC_CI_SIZE; - L1->end_ci = L1->base_ci + L1->size_ci; -} - - -static void freestack (lua_State *L, lua_State *L1) { - luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); - luaM_freearray(L, L1->stack, L1->stacksize, TObject); -} - - -/* -** open parts that may cause memory-allocation errors -*/ -static void f_luaopen (lua_State *L, void *ud) { - /* create a new global state */ - global_State *g = luaM_new(NULL, global_State); - UNUSED(ud); - if (g == NULL) luaD_throw(L, LUA_ERRMEM); - L->l_G = g; - g->mainthread = L; - g->GCthreshold = 0; /* mark it as unfinished state */ - g->strt.size = 0; - g->strt.nuse = 0; - g->strt.hash = NULL; - setnilvalue(defaultmeta(L)); - setnilvalue(registry(L)); - luaZ_initbuffer(L, &g->buff); - g->panic = default_panic; - g->rootgc = NULL; - g->rootudata = NULL; - g->tmudata = NULL; - setnilvalue(gkey(g->dummynode)); - setnilvalue(gval(g->dummynode)); - g->dummynode->next = NULL; - g->nblocks = sizeof(lua_State) + sizeof(global_State); - stack_init(L, L); /* init stack */ - /* create default meta table with a dummy table, and then close the loop */ - defaultmeta(L)->tt = LUA_TTABLE; - sethvalue(defaultmeta(L), luaH_new(L, 0, 0)); - hvalue(defaultmeta(L))->metatable = hvalue(defaultmeta(L)); - sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */ - sethvalue(registry(L), luaH_new(L, 4, 4)); /* registry */ - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ - luaT_init(L); - luaX_init(L); - luaS_fix(luaS_newliteral(L, MEMERRMSG)); - g->GCthreshold = 4*G(L)->nblocks; -} - - -static void preinit_state (lua_State *L) { - L->stack = NULL; - L->stacksize = 0; - L->errorJmp = NULL; - L->hook = NULL; - L->hookmask = L->hookinit = 0; - L->basehookcount = 0; - L->allowhook = 1; - resethookcount(L); - L->openupval = NULL; - L->size_ci = 0; - L->nCcalls = 0; - L->base_ci = L->ci = NULL; - L->errfunc = 0; - setnilvalue(gt(L)); -} - - -static void close_state (lua_State *L) { - luaF_close(L, L->stack); /* close all upvalues for this thread */ - if (G(L)) { /* close global state */ - luaC_sweep(L, 1); /* collect all elements */ - lua_assert(G(L)->rootgc == NULL); - lua_assert(G(L)->rootudata == NULL); - luaS_freeall(L); - luaZ_freebuffer(L, &G(L)->buff); - } - freestack(L, L); - if (G(L)) { - lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State)); - luaM_freelem(NULL, G(L)); - } - freestate(NULL, L); -} - - -lua_State *luaE_newthread (lua_State *L) { - lua_State *L1 = mallocstate(L); - luaC_link(L, valtogco(L1), LUA_TTHREAD); - preinit_state(L1); - L1->l_G = L->l_G; - stack_init(L1, L); /* init stack */ - setobj2n(gt(L1), gt(L)); /* share table of globals */ - return L1; -} - - -void luaE_freethread (lua_State *L, lua_State *L1) { - luaF_close(L1, L1->stack); /* close all upvalues for this thread */ - lua_assert(L1->openupval == NULL); - freestack(L, L1); - freestate(L, L1); -} - - -LUA_API lua_State *lua_open (void) { - lua_State *L = mallocstate(NULL); - if (L) { /* allocation OK? */ - L->tt = LUA_TTHREAD; - L->marked = 0; - L->next = L->gclist = NULL; - preinit_state(L); - L->l_G = NULL; - if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { - /* memory allocation error: free partial state */ - close_state(L); - L = NULL; - } - } - lua_userstateopen(L); - return L; -} - - -static void callallgcTM (lua_State *L, void *ud) { - UNUSED(ud); - luaC_callGCTM(L); /* call GC metamethods for all udata */ -} - - -LUA_API void lua_close (lua_State *L) { - lua_lock(L); - L = G(L)->mainthread; /* only the main thread can be closed */ - luaF_close(L, L->stack); /* close all upvalues for this thread */ - luaC_separateudata(L); /* separate udata that have GC metamethods */ - L->errfunc = 0; /* no error function during GC metamethods */ - do { /* repeat until no more errors */ - L->ci = L->base_ci; - L->base = L->top = L->ci->base; - L->nCcalls = 0; - } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); - lua_assert(G(L)->tmudata == NULL); - close_state(L); -} - +/*
+** $Id: lstate.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Global State
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdlib.h>
+
+#define lstate_c
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+/*
+** macro to allow the inclusion of user information in Lua state
+*/
+#ifndef LUA_USERSTATE
+#define EXTRASPACE 0
+#else
+union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;};
+#define EXTRASPACE (sizeof(union UEXTRASPACE))
+#endif
+
+
+
+/*
+** you can change this function through the official API:
+** call `lua_setpanicf'
+*/
+static int default_panic (lua_State *L) {
+ UNUSED(L);
+ return 0;
+}
+
+
+static lua_State *mallocstate (lua_State *L) {
+ lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE);
+ if (block == NULL) return NULL;
+ else {
+ block += EXTRASPACE;
+ return cast(lua_State *, block);
+ }
+}
+
+
+static void freestate (lua_State *L, lua_State *L1) {
+ luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE,
+ sizeof(lua_State) + EXTRASPACE);
+}
+
+
+static void stack_init (lua_State *L1, lua_State *L) {
+ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject);
+ L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
+ L1->top = L1->stack;
+ L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
+ L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);
+ L1->ci = L1->base_ci;
+ L1->ci->state = CI_C; /* not a Lua function */
+ setnilvalue(L1->top++); /* `function' entry for this `ci' */
+ L1->base = L1->ci->base = L1->top;
+ L1->ci->top = L1->top + LUA_MINSTACK;
+ L1->size_ci = BASIC_CI_SIZE;
+ L1->end_ci = L1->base_ci + L1->size_ci;
+}
+
+
+static void freestack (lua_State *L, lua_State *L1) {
+ luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo);
+ luaM_freearray(L, L1->stack, L1->stacksize, TObject);
+}
+
+
+/*
+** open parts that may cause memory-allocation errors
+*/
+static void f_luaopen (lua_State *L, void *ud) {
+ /* create a new global state */
+ global_State *g = luaM_new(NULL, global_State);
+ UNUSED(ud);
+ if (g == NULL) luaD_throw(L, LUA_ERRMEM);
+ L->l_G = g;
+ g->mainthread = L;
+ g->GCthreshold = 0; /* mark it as unfinished state */
+ g->strt.size = 0;
+ g->strt.nuse = 0;
+ g->strt.hash = NULL;
+ setnilvalue(defaultmeta(L));
+ setnilvalue(registry(L));
+ luaZ_initbuffer(L, &g->buff);
+ g->panic = default_panic;
+ g->rootgc = NULL;
+ g->rootudata = NULL;
+ g->tmudata = NULL;
+ setnilvalue(gkey(g->dummynode));
+ setnilvalue(gval(g->dummynode));
+ g->dummynode->next = NULL;
+ g->nblocks = sizeof(lua_State) + sizeof(global_State);
+ stack_init(L, L); /* init stack */
+ /* create default meta table with a dummy table, and then close the loop */
+ defaultmeta(L)->tt = LUA_TTABLE;
+ sethvalue(defaultmeta(L), luaH_new(L, 0, 0));
+ hvalue(defaultmeta(L))->metatable = hvalue(defaultmeta(L));
+ sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */
+ sethvalue(registry(L), luaH_new(L, 4, 4)); /* registry */
+ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
+ luaT_init(L);
+ luaX_init(L);
+ luaS_fix(luaS_newliteral(L, MEMERRMSG));
+ g->GCthreshold = 4*G(L)->nblocks;
+}
+
+
+static void preinit_state (lua_State *L) {
+ L->stack = NULL;
+ L->stacksize = 0;
+ L->errorJmp = NULL;
+ L->hook = NULL;
+ L->hookmask = L->hookinit = 0;
+ L->basehookcount = 0;
+ L->allowhook = 1;
+ resethookcount(L);
+ L->openupval = NULL;
+ L->size_ci = 0;
+ L->nCcalls = 0;
+ L->base_ci = L->ci = NULL;
+ L->errfunc = 0;
+ setnilvalue(gt(L));
+}
+
+
+static void close_state (lua_State *L) {
+ luaF_close(L, L->stack); /* close all upvalues for this thread */
+ if (G(L)) { /* close global state */
+ luaC_sweep(L, 1); /* collect all elements */
+ lua_assert(G(L)->rootgc == NULL);
+ lua_assert(G(L)->rootudata == NULL);
+ luaS_freeall(L);
+ luaZ_freebuffer(L, &G(L)->buff);
+ }
+ freestack(L, L);
+ if (G(L)) {
+ lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State));
+ luaM_freelem(NULL, G(L));
+ }
+ freestate(NULL, L);
+}
+
+
+lua_State *luaE_newthread (lua_State *L) {
+ lua_State *L1 = mallocstate(L);
+ luaC_link(L, valtogco(L1), LUA_TTHREAD);
+ preinit_state(L1);
+ L1->l_G = L->l_G;
+ stack_init(L1, L); /* init stack */
+ setobj2n(gt(L1), gt(L)); /* share table of globals */
+ return L1;
+}
+
+
+void luaE_freethread (lua_State *L, lua_State *L1) {
+ luaF_close(L1, L1->stack); /* close all upvalues for this thread */
+ lua_assert(L1->openupval == NULL);
+ freestack(L, L1);
+ freestate(L, L1);
+}
+
+
+LUA_API lua_State *lua_open (void) {
+ lua_State *L = mallocstate(NULL);
+ if (L) { /* allocation OK? */
+ L->tt = LUA_TTHREAD;
+ L->marked = 0;
+ L->next = L->gclist = NULL;
+ preinit_state(L);
+ L->l_G = NULL;
+ if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
+ /* memory allocation error: free partial state */
+ close_state(L);
+ L = NULL;
+ }
+ }
+ lua_userstateopen(L);
+ return L;
+}
+
+
+static void callallgcTM (lua_State *L, void *ud) {
+ UNUSED(ud);
+ luaC_callGCTM(L); /* call GC metamethods for all udata */
+}
+
+
+LUA_API void lua_close (lua_State *L) {
+ lua_lock(L);
+ L = G(L)->mainthread; /* only the main thread can be closed */
+ luaF_close(L, L->stack); /* close all upvalues for this thread */
+ luaC_separateudata(L); /* separate udata that have GC metamethods */
+ L->errfunc = 0; /* no error function during GC metamethods */
+ do { /* repeat until no more errors */
+ L->ci = L->base_ci;
+ L->base = L->top = L->ci->base;
+ L->nCcalls = 0;
+ } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0);
+ lua_assert(G(L)->tmudata == NULL);
+ close_state(L);
+}
+
diff --git a/lib/lua/src/lstring.c b/lib/lua/src/lstring.c index 2d6f5e5..863f510 100644 --- a/lib/lua/src/lstring.c +++ b/lib/lua/src/lstring.c @@ -1,102 +1,102 @@ -/* -** $Id: lstring.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** String table (keeps all strings handled by Lua) -** See Copyright Notice in lua.h -*/ - - -#include <string.h> - -#define lstring_c - -#include "lua.h" - -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" - - - -void luaS_freeall (lua_State *L) { - lua_assert(G(L)->strt.nuse==0); - luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); -} - - -void luaS_resize (lua_State *L, int newsize) { - GCObject **newhash = luaM_newvector(L, newsize, GCObject *); - stringtable *tb = &G(L)->strt; - int i; - for (i=0; i<newsize; i++) newhash[i] = NULL; - /* rehash */ - for (i=0; i<tb->size; i++) { - GCObject *p = tb->hash[i]; - while (p) { /* for each node in the list */ - GCObject *next = p->gch.next; /* save next */ - lu_hash h = gcotots(p)->tsv.hash; - int h1 = lmod(h, newsize); /* new position */ - lua_assert(cast(int, h%newsize) == lmod(h, newsize)); - p->gch.next = newhash[h1]; /* chain it */ - newhash[h1] = p; - p = next; - } - } - luaM_freearray(L, tb->hash, tb->size, TString *); - tb->size = newsize; - tb->hash = newhash; -} - - -static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) { - TString *ts = cast(TString *, luaM_malloc(L, sizestring(l))); - stringtable *tb; - ts->tsv.len = l; - ts->tsv.hash = h; - ts->tsv.marked = 0; - ts->tsv.tt = LUA_TSTRING; - ts->tsv.reserved = 0; - memcpy(ts+1, str, l*sizeof(char)); - ((char *)(ts+1))[l] = '\0'; /* ending 0 */ - tb = &G(L)->strt; - h = lmod(h, tb->size); - ts->tsv.next = tb->hash[h]; /* chain new entry */ - tb->hash[h] = valtogco(ts); - tb->nuse++; - if (tb->nuse > cast(ls_nstr, tb->size) && tb->size <= MAX_INT/2) - luaS_resize(L, tb->size*2); /* too crowded */ - return ts; -} - - -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - GCObject *o; - lu_hash h = (lu_hash)l; /* seed */ - size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ - size_t l1; - for (l1=l; l1>=step; l1-=step) /* compute hash */ - h = h ^ ((h<<5)+(h>>2)+(unsigned char)(str[l1-1])); - for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; - o != NULL; - o = o->gch.next) { - TString *ts = gcotots(o); - if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) - return ts; - } - return newlstr(L, str, l, h); /* not found */ -} - - -Udata *luaS_newudata (lua_State *L, size_t s) { - Udata *u; - u = cast(Udata *, luaM_malloc(L, sizeudata(s))); - u->uv.marked = (1<<1); /* is not finalized */ - u->uv.tt = LUA_TUSERDATA; - u->uv.len = s; - u->uv.metatable = hvalue(defaultmeta(L)); - /* chain it on udata list */ - u->uv.next = G(L)->rootudata; - G(L)->rootudata = valtogco(u); - return u; -} - +/*
+** $Id: lstring.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** String table (keeps all strings handled by Lua)
+** See Copyright Notice in lua.h
+*/
+
+
+#include <string.h>
+
+#define lstring_c
+
+#include "lua.h"
+
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+
+
+
+void luaS_freeall (lua_State *L) {
+ lua_assert(G(L)->strt.nuse==0);
+ luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
+}
+
+
+void luaS_resize (lua_State *L, int newsize) {
+ GCObject **newhash = luaM_newvector(L, newsize, GCObject *);
+ stringtable *tb = &G(L)->strt;
+ int i;
+ for (i=0; i<newsize; i++) newhash[i] = NULL;
+ /* rehash */
+ for (i=0; i<tb->size; i++) {
+ GCObject *p = tb->hash[i];
+ while (p) { /* for each node in the list */
+ GCObject *next = p->gch.next; /* save next */
+ lu_hash h = gcotots(p)->tsv.hash;
+ int h1 = lmod(h, newsize); /* new position */
+ lua_assert(cast(int, h%newsize) == lmod(h, newsize));
+ p->gch.next = newhash[h1]; /* chain it */
+ newhash[h1] = p;
+ p = next;
+ }
+ }
+ luaM_freearray(L, tb->hash, tb->size, TString *);
+ tb->size = newsize;
+ tb->hash = newhash;
+}
+
+
+static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) {
+ TString *ts = cast(TString *, luaM_malloc(L, sizestring(l)));
+ stringtable *tb;
+ ts->tsv.len = l;
+ ts->tsv.hash = h;
+ ts->tsv.marked = 0;
+ ts->tsv.tt = LUA_TSTRING;
+ ts->tsv.reserved = 0;
+ memcpy(ts+1, str, l*sizeof(char));
+ ((char *)(ts+1))[l] = '\0'; /* ending 0 */
+ tb = &G(L)->strt;
+ h = lmod(h, tb->size);
+ ts->tsv.next = tb->hash[h]; /* chain new entry */
+ tb->hash[h] = valtogco(ts);
+ tb->nuse++;
+ if (tb->nuse > cast(ls_nstr, tb->size) && tb->size <= MAX_INT/2)
+ luaS_resize(L, tb->size*2); /* too crowded */
+ return ts;
+}
+
+
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
+ GCObject *o;
+ lu_hash h = (lu_hash)l; /* seed */
+ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
+ size_t l1;
+ for (l1=l; l1>=step; l1-=step) /* compute hash */
+ h = h ^ ((h<<5)+(h>>2)+(unsigned char)(str[l1-1]));
+ for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
+ o != NULL;
+ o = o->gch.next) {
+ TString *ts = gcotots(o);
+ if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0))
+ return ts;
+ }
+ return newlstr(L, str, l, h); /* not found */
+}
+
+
+Udata *luaS_newudata (lua_State *L, size_t s) {
+ Udata *u;
+ u = cast(Udata *, luaM_malloc(L, sizeudata(s)));
+ u->uv.marked = (1<<1); /* is not finalized */
+ u->uv.tt = LUA_TUSERDATA;
+ u->uv.len = s;
+ u->uv.metatable = hvalue(defaultmeta(L));
+ /* chain it on udata list */
+ u->uv.next = G(L)->rootudata;
+ G(L)->rootudata = valtogco(u);
+ return u;
+}
+
diff --git a/lib/lua/src/ltable.c b/lib/lua/src/ltable.c index cd5e576..9f4cb6c 100644 --- a/lib/lua/src/ltable.c +++ b/lib/lua/src/ltable.c @@ -1,509 +1,509 @@ -/* -** $Id: ltable.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - - -/* -** Implementation of tables (aka arrays, objects, or hash tables). -** Tables keep its elements in two parts: an array part and a hash part. -** Non-negative integer keys are all candidates to be kept in the array -** part. The actual size of the array is the largest `n' such that at -** least half the slots between 0 and n are in use. -** Hash uses a mix of chained scatter table with Brent's variation. -** A main invariant of these tables is that, if an element is not -** in its main position (i.e. the `original' position that its hash gives -** to it), then the colliding element is in its own main position. -** In other words, there are collisions only when two elements have the -** same main position (i.e. the same hash values for that table size). -** Because of that, the load factor of these tables can be 100% without -** performance penalties. -*/ - -#include <string.h> - -#define ltable_c - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lgc.h" -#include "lmem.h" -#include "lobject.h" -#include "lstate.h" -#include "ltable.h" - - -/* -** max size of array part is 2^MAXBITS -*/ -#if BITS_INT > 26 -#define MAXBITS 24 -#else -#define MAXBITS (BITS_INT-2) -#endif - -/* check whether `x' < 2^MAXBITS */ -#define toobig(x) ((((x)-1) >> MAXBITS) != 0) - - -/* function to convert a lua_Number to int (with any rounding method) */ -#ifndef lua_number2int -#define lua_number2int(i,n) ((i)=(int)(n)) -#endif - - -#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) - -#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) -#define hashboolean(t,p) hashpow2(t, p) - - -/* -** for some types, it is better to avoid modulus by power of 2, as -** they tend to have many 2 factors. -*/ -#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) - - -#define hashpointer(t,p) hashmod(t, IntPoint(p)) - - -/* -** number of ints inside a lua_Number -*/ -#define numints cast(int, sizeof(lua_Number)/sizeof(int)) - - -/* -** hash for lua_Numbers -*/ -static Node *hashnum (const Table *t, lua_Number n) { - unsigned int a[numints]; - int i; - n += 1; /* normalize number (avoid -0) */ - lua_assert(sizeof(a) <= sizeof(n)); - memcpy(a, &n, sizeof(a)); - for (i = 1; i < numints; i++) a[0] += a[i]; - return hashmod(t, cast(lu_hash, a[0])); -} - - - -/* -** returns the `main' position of an element in a table (that is, the index -** of its hash value) -*/ -Node *luaH_mainposition (const Table *t, const TObject *key) { - switch (ttype(key)) { - case LUA_TNUMBER: - return hashnum(t, nvalue(key)); - case LUA_TSTRING: - return hashstr(t, tsvalue(key)); - case LUA_TBOOLEAN: - return hashboolean(t, bvalue(key)); - case LUA_TLIGHTUSERDATA: - return hashpointer(t, pvalue(key)); - default: - return hashpointer(t, gcvalue(key)); - } -} - - -/* -** returns the index for `key' if `key' is an appropriate key to live in -** the array part of the table, -1 otherwise. -*/ -static int arrayindex (const TObject *key) { - if (ttisnumber(key)) { - int k; - lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k)) - return k; - } - return -1; /* `key' did not match some condition */ -} - - -/* -** returns the index of a `key' for table traversals. First goes all -** elements in the array part, then elements in the hash part. The -** beginning and end of a traversal are signalled by -1. -*/ -static int luaH_index (lua_State *L, Table *t, StkId key) { - int i; - if (ttisnil(key)) return -1; /* first iteration */ - i = arrayindex(key); - if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */ - return i-1; /* yes; that's the index (corrected to C) */ - } - else { - const TObject *v = luaH_get(t, key); - if (v == &luaO_nilobject) - luaG_runerror(L, "invalid key for `next'"); - i = cast(int, (cast(const lu_byte *, v) - - cast(const lu_byte *, gval(gnode(t, 0)))) / sizeof(Node)); - return i + t->sizearray; /* hash elements are numbered after array ones */ - } -} - - -int luaH_next (lua_State *L, Table *t, StkId key) { - int i = luaH_index(L, t, key); /* find original element */ - for (i++; i < t->sizearray; i++) { /* try first array part */ - if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setnvalue(key, cast(lua_Number, i+1)); - setobj2s(key+1, &t->array[i]); - return 1; - } - } - for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ - if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(key, gkey(gnode(t, i))); - setobj2s(key+1, gval(gnode(t, i))); - return 1; - } - } - return 0; /* no more elements */ -} - - -/* -** {============================================================= -** Rehash -** ============================================================== -*/ - - -static void computesizes (int nums[], int ntotal, int *narray, int *nhash) { - int i; - int a = nums[0]; /* number of elements smaller than 2^i */ - int na = a; /* number of elements to go to array part */ - int n = (na == 0) ? -1 : 0; /* (log of) optimal size for array part */ - for (i = 1; a < *narray && *narray >= twoto(i-1); i++) { - if (nums[i] > 0) { - a += nums[i]; - if (a >= twoto(i-1)) { /* more than half elements in use? */ - n = i; - na = a; - } - } - } - lua_assert(na <= *narray && *narray <= ntotal); - *nhash = ntotal - na; - *narray = (n == -1) ? 0 : twoto(n); - lua_assert(na <= *narray && na >= *narray/2); -} - - -static void numuse (const Table *t, int *narray, int *nhash) { - int nums[MAXBITS+1]; - int i, lg; - int totaluse = 0; - /* count elements in array part */ - for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */ - int ttlg = twoto(lg); /* 2^lg */ - if (ttlg > t->sizearray) { - ttlg = t->sizearray; - if (i >= ttlg) break; - } - nums[lg] = 0; - for (; i<ttlg; i++) { - if (!ttisnil(&t->array[i])) { - nums[lg]++; - totaluse++; - } - } - } - for (; lg<=MAXBITS; lg++) nums[lg] = 0; /* reset other counts */ - *narray = totaluse; /* all previous uses were in array part */ - /* count elements in hash part */ - i = sizenode(t); - while (i--) { - Node *n = &t->node[i]; - if (!ttisnil(gval(n))) { - int k = arrayindex(gkey(n)); - if (k >= 0) { /* is `key' an appropriate array index? */ - nums[luaO_log2(k-1)+1]++; /* count as such */ - (*narray)++; - } - totaluse++; - } - } - computesizes(nums, totaluse, narray, nhash); -} - - -static void setarrayvector (lua_State *L, Table *t, int size) { - int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TObject); - for (i=t->sizearray; i<size; i++) - setnilvalue(&t->array[i]); - t->sizearray = size; -} - - -static void setnodevector (lua_State *L, Table *t, int lsize) { - int i; - int size = twoto(lsize); - if (lsize > MAXBITS) - luaG_runerror(L, "table overflow"); - if (lsize == 0) { /* no elements to hash part? */ - t->node = G(L)->dummynode; /* use common `dummynode' */ - lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */ - lua_assert(ttisnil(gval(t->node))); - lua_assert(t->node->next == NULL); /* (`dummynode' must be empty) */ - } - else { - t->node = luaM_newvector(L, size, Node); - for (i=0; i<size; i++) { - t->node[i].next = NULL; - setnilvalue(gkey(gnode(t, i))); - setnilvalue(gval(gnode(t, i))); - } - } - t->lsizenode = cast(lu_byte, lsize); - t->firstfree = gnode(t, size-1); /* first free position to be used */ -} - - -static void resize (lua_State *L, Table *t, int nasize, int nhsize) { - int i; - int oldasize = t->sizearray; - int oldhsize = t->lsizenode; - Node *nold; - Node temp[1]; - if (oldhsize) - nold = t->node; /* save old hash ... */ - else { /* old hash is `dummynode' */ - lua_assert(t->node == G(L)->dummynode); - temp[0] = t->node[0]; /* copy it to `temp' */ - nold = temp; - setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */ - setnilvalue(gval(G(L)->dummynode)); - lua_assert(G(L)->dummynode->next == NULL); - } - if (nasize > oldasize) /* array part must grow? */ - setarrayvector(L, t, nasize); - /* create new hash part with appropriate size */ - setnodevector(L, t, nhsize); - /* re-insert elements */ - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ - for (i=nasize; i<oldasize; i++) { - if (!ttisnil(&t->array[i])) - setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]); - } - /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TObject); - } - /* re-insert elements in hash part */ - for (i = twoto(oldhsize) - 1; i >= 0; i--) { - Node *old = nold+i; - if (!ttisnil(gval(old))) - setobjt2t(luaH_set(L, t, gkey(old)), gval(old)); - } - if (oldhsize) - luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */ -} - - -static void rehash (lua_State *L, Table *t) { - int nasize, nhsize; - numuse(t, &nasize, &nhsize); /* compute new sizes for array and hash parts */ - resize(L, t, nasize, luaO_log2(nhsize)+1); -} - - - -/* -** }============================================================= -*/ - - -Table *luaH_new (lua_State *L, int narray, int lnhash) { - Table *t = luaM_new(L, Table); - luaC_link(L, valtogco(t), LUA_TTABLE); - t->metatable = hvalue(defaultmeta(L)); - t->flags = cast(lu_byte, ~0); - /* temporary values (kept only if some malloc fails) */ - t->array = NULL; - t->sizearray = 0; - t->lsizenode = 0; - t->node = NULL; - setarrayvector(L, t, narray); - setnodevector(L, t, lnhash); - return t; -} - - -void luaH_free (lua_State *L, Table *t) { - if (t->lsizenode) - luaM_freearray(L, t->node, sizenode(t), Node); - luaM_freearray(L, t->array, t->sizearray, TObject); - luaM_freelem(L, t); -} - - -#if 0 -/* -** try to remove an element from a hash table; cannot move any element -** (because gc can call `remove' during a table traversal) -*/ -void luaH_remove (Table *t, Node *e) { - Node *mp = luaH_mainposition(t, gkey(e)); - if (e != mp) { /* element not in its main position? */ - while (mp->next != e) mp = mp->next; /* find previous */ - mp->next = e->next; /* remove `e' from its list */ - } - else { - if (e->next != NULL) ?? - } - lua_assert(ttisnil(gval(node))); - setnilvalue(gkey(e)); /* clear node `e' */ - e->next = NULL; -} -#endif - - -/* -** inserts a new key into a hash table; first, check whether key's main -** position is free. If not, check whether colliding node is in its main -** position or not: if it is not, move colliding node to an empty place and -** put new key in its main position; otherwise (colliding node is in its main -** position), new key goes to an empty position. -*/ -static TObject *newkey (lua_State *L, Table *t, const TObject *key) { - TObject *val; - Node *mp = luaH_mainposition(t, key); - if (!ttisnil(gval(mp))) { /* main position is not free? */ - Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */ - Node *n = t->firstfree; /* get a free place */ - if (othern != mp) { /* is colliding node out of its main position? */ - /* yes; move colliding node into free position */ - while (othern->next != mp) othern = othern->next; /* find previous */ - othern->next = n; /* redo the chain with `n' in place of `mp' */ - *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - mp->next = NULL; /* now `mp' is free */ - setnilvalue(gval(mp)); - } - else { /* colliding node is in its own main position */ - /* new node will go into free position */ - n->next = mp->next; /* chain new position */ - mp->next = n; - mp = n; - } - } - setobj2t(gkey(mp), key); /* write barrier */ - lua_assert(ttisnil(gval(mp))); - for (;;) { /* correct `firstfree' */ - if (ttisnil(gkey(t->firstfree))) - return gval(mp); /* OK; table still has a free place */ - else if (t->firstfree == t->node) break; /* cannot decrement from here */ - else (t->firstfree)--; - } - /* no more free places; must create one */ - setbvalue(gval(mp), 0); /* avoid new key being removed */ - rehash(L, t); /* grow table */ - val = cast(TObject *, luaH_get(t, key)); /* get new position */ - lua_assert(ttisboolean(val)); - setnilvalue(val); - return val; -} - - -/* -** generic search function -*/ -static const TObject *luaH_getany (Table *t, const TObject *key) { - if (ttisnil(key)) return &luaO_nilobject; - else { - Node *n = luaH_mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */ - else n = n->next; - } while (n); - return &luaO_nilobject; - } -} - - -/* -** search function for integers -*/ -const TObject *luaH_getnum (Table *t, int key) { - if (1 <= key && key <= t->sizearray) - return &t->array[key-1]; - else { - lua_Number nk = cast(lua_Number, key); - Node *n = hashnum(t, nk); - do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk) - return gval(n); /* that's it */ - else n = n->next; - } while (n); - return &luaO_nilobject; - } -} - - -/* -** search function for strings -*/ -const TObject *luaH_getstr (Table *t, TString *key) { - Node *n = hashstr(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key) - return gval(n); /* that's it */ - else n = n->next; - } while (n); - return &luaO_nilobject; -} - - -/* -** main search function -*/ -const TObject *luaH_get (Table *t, const TObject *key) { - switch (ttype(key)) { - case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); - case LUA_TNUMBER: { - int k; - lua_number2int(k, (nvalue(key))); - if (cast(lua_Number, k) == nvalue(key)) /* is an integer index? */ - return luaH_getnum(t, k); /* use specialized version */ - /* else go through */ - } - default: return luaH_getany(t, key); - } -} - - -TObject *luaH_set (lua_State *L, Table *t, const TObject *key) { - const TObject *p = luaH_get(t, key); - t->flags = 0; - if (p != &luaO_nilobject) - return cast(TObject *, p); - else { - if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && nvalue(key) != nvalue(key)) - luaG_runerror(L, "table index is NaN"); - return newkey(L, t, key); - } -} - - -TObject *luaH_setnum (lua_State *L, Table *t, int key) { - const TObject *p = luaH_getnum(t, key); - if (p != &luaO_nilobject) - return cast(TObject *, p); - else { - TObject k; - setnvalue(&k, cast(lua_Number, key)); - return newkey(L, t, &k); - } -} - +/*
+** $Id: ltable.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Lua tables (hash)
+** See Copyright Notice in lua.h
+*/
+
+
+/*
+** Implementation of tables (aka arrays, objects, or hash tables).
+** Tables keep its elements in two parts: an array part and a hash part.
+** Non-negative integer keys are all candidates to be kept in the array
+** part. The actual size of the array is the largest `n' such that at
+** least half the slots between 0 and n are in use.
+** Hash uses a mix of chained scatter table with Brent's variation.
+** A main invariant of these tables is that, if an element is not
+** in its main position (i.e. the `original' position that its hash gives
+** to it), then the colliding element is in its own main position.
+** In other words, there are collisions only when two elements have the
+** same main position (i.e. the same hash values for that table size).
+** Because of that, the load factor of these tables can be 100% without
+** performance penalties.
+*/
+
+#include <string.h>
+
+#define ltable_c
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "ltable.h"
+
+
+/*
+** max size of array part is 2^MAXBITS
+*/
+#if BITS_INT > 26
+#define MAXBITS 24
+#else
+#define MAXBITS (BITS_INT-2)
+#endif
+
+/* check whether `x' < 2^MAXBITS */
+#define toobig(x) ((((x)-1) >> MAXBITS) != 0)
+
+
+/* function to convert a lua_Number to int (with any rounding method) */
+#ifndef lua_number2int
+#define lua_number2int(i,n) ((i)=(int)(n))
+#endif
+
+
+#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
+
+#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
+#define hashboolean(t,p) hashpow2(t, p)
+
+
+/*
+** for some types, it is better to avoid modulus by power of 2, as
+** they tend to have many 2 factors.
+*/
+#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
+
+
+#define hashpointer(t,p) hashmod(t, IntPoint(p))
+
+
+/*
+** number of ints inside a lua_Number
+*/
+#define numints cast(int, sizeof(lua_Number)/sizeof(int))
+
+
+/*
+** hash for lua_Numbers
+*/
+static Node *hashnum (const Table *t, lua_Number n) {
+ unsigned int a[numints];
+ int i;
+ n += 1; /* normalize number (avoid -0) */
+ lua_assert(sizeof(a) <= sizeof(n));
+ memcpy(a, &n, sizeof(a));
+ for (i = 1; i < numints; i++) a[0] += a[i];
+ return hashmod(t, cast(lu_hash, a[0]));
+}
+
+
+
+/*
+** returns the `main' position of an element in a table (that is, the index
+** of its hash value)
+*/
+Node *luaH_mainposition (const Table *t, const TObject *key) {
+ switch (ttype(key)) {
+ case LUA_TNUMBER:
+ return hashnum(t, nvalue(key));
+ case LUA_TSTRING:
+ return hashstr(t, tsvalue(key));
+ case LUA_TBOOLEAN:
+ return hashboolean(t, bvalue(key));
+ case LUA_TLIGHTUSERDATA:
+ return hashpointer(t, pvalue(key));
+ default:
+ return hashpointer(t, gcvalue(key));
+ }
+}
+
+
+/*
+** returns the index for `key' if `key' is an appropriate key to live in
+** the array part of the table, -1 otherwise.
+*/
+static int arrayindex (const TObject *key) {
+ if (ttisnumber(key)) {
+ int k;
+ lua_number2int(k, (nvalue(key)));
+ if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k))
+ return k;
+ }
+ return -1; /* `key' did not match some condition */
+}
+
+
+/*
+** returns the index of a `key' for table traversals. First goes all
+** elements in the array part, then elements in the hash part. The
+** beginning and end of a traversal are signalled by -1.
+*/
+static int luaH_index (lua_State *L, Table *t, StkId key) {
+ int i;
+ if (ttisnil(key)) return -1; /* first iteration */
+ i = arrayindex(key);
+ if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */
+ return i-1; /* yes; that's the index (corrected to C) */
+ }
+ else {
+ const TObject *v = luaH_get(t, key);
+ if (v == &luaO_nilobject)
+ luaG_runerror(L, "invalid key for `next'");
+ i = cast(int, (cast(const lu_byte *, v) -
+ cast(const lu_byte *, gval(gnode(t, 0)))) / sizeof(Node));
+ return i + t->sizearray; /* hash elements are numbered after array ones */
+ }
+}
+
+
+int luaH_next (lua_State *L, Table *t, StkId key) {
+ int i = luaH_index(L, t, key); /* find original element */
+ for (i++; i < t->sizearray; i++) { /* try first array part */
+ if (!ttisnil(&t->array[i])) { /* a non-nil value? */
+ setnvalue(key, cast(lua_Number, i+1));
+ setobj2s(key+1, &t->array[i]);
+ return 1;
+ }
+ }
+ for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */
+ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
+ setobj2s(key, gkey(gnode(t, i)));
+ setobj2s(key+1, gval(gnode(t, i)));
+ return 1;
+ }
+ }
+ return 0; /* no more elements */
+}
+
+
+/*
+** {=============================================================
+** Rehash
+** ==============================================================
+*/
+
+
+static void computesizes (int nums[], int ntotal, int *narray, int *nhash) {
+ int i;
+ int a = nums[0]; /* number of elements smaller than 2^i */
+ int na = a; /* number of elements to go to array part */
+ int n = (na == 0) ? -1 : 0; /* (log of) optimal size for array part */
+ for (i = 1; a < *narray && *narray >= twoto(i-1); i++) {
+ if (nums[i] > 0) {
+ a += nums[i];
+ if (a >= twoto(i-1)) { /* more than half elements in use? */
+ n = i;
+ na = a;
+ }
+ }
+ }
+ lua_assert(na <= *narray && *narray <= ntotal);
+ *nhash = ntotal - na;
+ *narray = (n == -1) ? 0 : twoto(n);
+ lua_assert(na <= *narray && na >= *narray/2);
+}
+
+
+static void numuse (const Table *t, int *narray, int *nhash) {
+ int nums[MAXBITS+1];
+ int i, lg;
+ int totaluse = 0;
+ /* count elements in array part */
+ for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */
+ int ttlg = twoto(lg); /* 2^lg */
+ if (ttlg > t->sizearray) {
+ ttlg = t->sizearray;
+ if (i >= ttlg) break;
+ }
+ nums[lg] = 0;
+ for (; i<ttlg; i++) {
+ if (!ttisnil(&t->array[i])) {
+ nums[lg]++;
+ totaluse++;
+ }
+ }
+ }
+ for (; lg<=MAXBITS; lg++) nums[lg] = 0; /* reset other counts */
+ *narray = totaluse; /* all previous uses were in array part */
+ /* count elements in hash part */
+ i = sizenode(t);
+ while (i--) {
+ Node *n = &t->node[i];
+ if (!ttisnil(gval(n))) {
+ int k = arrayindex(gkey(n));
+ if (k >= 0) { /* is `key' an appropriate array index? */
+ nums[luaO_log2(k-1)+1]++; /* count as such */
+ (*narray)++;
+ }
+ totaluse++;
+ }
+ }
+ computesizes(nums, totaluse, narray, nhash);
+}
+
+
+static void setarrayvector (lua_State *L, Table *t, int size) {
+ int i;
+ luaM_reallocvector(L, t->array, t->sizearray, size, TObject);
+ for (i=t->sizearray; i<size; i++)
+ setnilvalue(&t->array[i]);
+ t->sizearray = size;
+}
+
+
+static void setnodevector (lua_State *L, Table *t, int lsize) {
+ int i;
+ int size = twoto(lsize);
+ if (lsize > MAXBITS)
+ luaG_runerror(L, "table overflow");
+ if (lsize == 0) { /* no elements to hash part? */
+ t->node = G(L)->dummynode; /* use common `dummynode' */
+ lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */
+ lua_assert(ttisnil(gval(t->node)));
+ lua_assert(t->node->next == NULL); /* (`dummynode' must be empty) */
+ }
+ else {
+ t->node = luaM_newvector(L, size, Node);
+ for (i=0; i<size; i++) {
+ t->node[i].next = NULL;
+ setnilvalue(gkey(gnode(t, i)));
+ setnilvalue(gval(gnode(t, i)));
+ }
+ }
+ t->lsizenode = cast(lu_byte, lsize);
+ t->firstfree = gnode(t, size-1); /* first free position to be used */
+}
+
+
+static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
+ int i;
+ int oldasize = t->sizearray;
+ int oldhsize = t->lsizenode;
+ Node *nold;
+ Node temp[1];
+ if (oldhsize)
+ nold = t->node; /* save old hash ... */
+ else { /* old hash is `dummynode' */
+ lua_assert(t->node == G(L)->dummynode);
+ temp[0] = t->node[0]; /* copy it to `temp' */
+ nold = temp;
+ setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */
+ setnilvalue(gval(G(L)->dummynode));
+ lua_assert(G(L)->dummynode->next == NULL);
+ }
+ if (nasize > oldasize) /* array part must grow? */
+ setarrayvector(L, t, nasize);
+ /* create new hash part with appropriate size */
+ setnodevector(L, t, nhsize);
+ /* re-insert elements */
+ if (nasize < oldasize) { /* array part must shrink? */
+ t->sizearray = nasize;
+ /* re-insert elements from vanishing slice */
+ for (i=nasize; i<oldasize; i++) {
+ if (!ttisnil(&t->array[i]))
+ setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]);
+ }
+ /* shrink array */
+ luaM_reallocvector(L, t->array, oldasize, nasize, TObject);
+ }
+ /* re-insert elements in hash part */
+ for (i = twoto(oldhsize) - 1; i >= 0; i--) {
+ Node *old = nold+i;
+ if (!ttisnil(gval(old)))
+ setobjt2t(luaH_set(L, t, gkey(old)), gval(old));
+ }
+ if (oldhsize)
+ luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */
+}
+
+
+static void rehash (lua_State *L, Table *t) {
+ int nasize, nhsize;
+ numuse(t, &nasize, &nhsize); /* compute new sizes for array and hash parts */
+ resize(L, t, nasize, luaO_log2(nhsize)+1);
+}
+
+
+
+/*
+** }=============================================================
+*/
+
+
+Table *luaH_new (lua_State *L, int narray, int lnhash) {
+ Table *t = luaM_new(L, Table);
+ luaC_link(L, valtogco(t), LUA_TTABLE);
+ t->metatable = hvalue(defaultmeta(L));
+ t->flags = cast(lu_byte, ~0);
+ /* temporary values (kept only if some malloc fails) */
+ t->array = NULL;
+ t->sizearray = 0;
+ t->lsizenode = 0;
+ t->node = NULL;
+ setarrayvector(L, t, narray);
+ setnodevector(L, t, lnhash);
+ return t;
+}
+
+
+void luaH_free (lua_State *L, Table *t) {
+ if (t->lsizenode)
+ luaM_freearray(L, t->node, sizenode(t), Node);
+ luaM_freearray(L, t->array, t->sizearray, TObject);
+ luaM_freelem(L, t);
+}
+
+
+#if 0
+/*
+** try to remove an element from a hash table; cannot move any element
+** (because gc can call `remove' during a table traversal)
+*/
+void luaH_remove (Table *t, Node *e) {
+ Node *mp = luaH_mainposition(t, gkey(e));
+ if (e != mp) { /* element not in its main position? */
+ while (mp->next != e) mp = mp->next; /* find previous */
+ mp->next = e->next; /* remove `e' from its list */
+ }
+ else {
+ if (e->next != NULL) ??
+ }
+ lua_assert(ttisnil(gval(node)));
+ setnilvalue(gkey(e)); /* clear node `e' */
+ e->next = NULL;
+}
+#endif
+
+
+/*
+** inserts a new key into a hash table; first, check whether key's main
+** position is free. If not, check whether colliding node is in its main
+** position or not: if it is not, move colliding node to an empty place and
+** put new key in its main position; otherwise (colliding node is in its main
+** position), new key goes to an empty position.
+*/
+static TObject *newkey (lua_State *L, Table *t, const TObject *key) {
+ TObject *val;
+ Node *mp = luaH_mainposition(t, key);
+ if (!ttisnil(gval(mp))) { /* main position is not free? */
+ Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */
+ Node *n = t->firstfree; /* get a free place */
+ if (othern != mp) { /* is colliding node out of its main position? */
+ /* yes; move colliding node into free position */
+ while (othern->next != mp) othern = othern->next; /* find previous */
+ othern->next = n; /* redo the chain with `n' in place of `mp' */
+ *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
+ mp->next = NULL; /* now `mp' is free */
+ setnilvalue(gval(mp));
+ }
+ else { /* colliding node is in its own main position */
+ /* new node will go into free position */
+ n->next = mp->next; /* chain new position */
+ mp->next = n;
+ mp = n;
+ }
+ }
+ setobj2t(gkey(mp), key); /* write barrier */
+ lua_assert(ttisnil(gval(mp)));
+ for (;;) { /* correct `firstfree' */
+ if (ttisnil(gkey(t->firstfree)))
+ return gval(mp); /* OK; table still has a free place */
+ else if (t->firstfree == t->node) break; /* cannot decrement from here */
+ else (t->firstfree)--;
+ }
+ /* no more free places; must create one */
+ setbvalue(gval(mp), 0); /* avoid new key being removed */
+ rehash(L, t); /* grow table */
+ val = cast(TObject *, luaH_get(t, key)); /* get new position */
+ lua_assert(ttisboolean(val));
+ setnilvalue(val);
+ return val;
+}
+
+
+/*
+** generic search function
+*/
+static const TObject *luaH_getany (Table *t, const TObject *key) {
+ if (ttisnil(key)) return &luaO_nilobject;
+ else {
+ Node *n = luaH_mainposition(t, key);
+ do { /* check whether `key' is somewhere in the chain */
+ if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */
+ else n = n->next;
+ } while (n);
+ return &luaO_nilobject;
+ }
+}
+
+
+/*
+** search function for integers
+*/
+const TObject *luaH_getnum (Table *t, int key) {
+ if (1 <= key && key <= t->sizearray)
+ return &t->array[key-1];
+ else {
+ lua_Number nk = cast(lua_Number, key);
+ Node *n = hashnum(t, nk);
+ do { /* check whether `key' is somewhere in the chain */
+ if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk)
+ return gval(n); /* that's it */
+ else n = n->next;
+ } while (n);
+ return &luaO_nilobject;
+ }
+}
+
+
+/*
+** search function for strings
+*/
+const TObject *luaH_getstr (Table *t, TString *key) {
+ Node *n = hashstr(t, key);
+ do { /* check whether `key' is somewhere in the chain */
+ if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key)
+ return gval(n); /* that's it */
+ else n = n->next;
+ } while (n);
+ return &luaO_nilobject;
+}
+
+
+/*
+** main search function
+*/
+const TObject *luaH_get (Table *t, const TObject *key) {
+ switch (ttype(key)) {
+ case LUA_TSTRING: return luaH_getstr(t, tsvalue(key));
+ case LUA_TNUMBER: {
+ int k;
+ lua_number2int(k, (nvalue(key)));
+ if (cast(lua_Number, k) == nvalue(key)) /* is an integer index? */
+ return luaH_getnum(t, k); /* use specialized version */
+ /* else go through */
+ }
+ default: return luaH_getany(t, key);
+ }
+}
+
+
+TObject *luaH_set (lua_State *L, Table *t, const TObject *key) {
+ const TObject *p = luaH_get(t, key);
+ t->flags = 0;
+ if (p != &luaO_nilobject)
+ return cast(TObject *, p);
+ else {
+ if (ttisnil(key)) luaG_runerror(L, "table index is nil");
+ else if (ttisnumber(key) && nvalue(key) != nvalue(key))
+ luaG_runerror(L, "table index is NaN");
+ return newkey(L, t, key);
+ }
+}
+
+
+TObject *luaH_setnum (lua_State *L, Table *t, int key) {
+ const TObject *p = luaH_getnum(t, key);
+ if (p != &luaO_nilobject)
+ return cast(TObject *, p);
+ else {
+ TObject k;
+ setnvalue(&k, cast(lua_Number, key));
+ return newkey(L, t, &k);
+ }
+}
+
diff --git a/lib/lua/src/ltests.c b/lib/lua/src/ltests.c index 79ae526..8e53314 100644 --- a/lib/lua/src/ltests.c +++ b/lib/lua/src/ltests.c @@ -1,852 +1,852 @@ -/* -** $Id: ltests.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Internal Module for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - - -#include <ctype.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define ltests_c - -#include "lua.h" - -#include "lapi.h" -#include "lauxlib.h" -#include "lcode.h" -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lmem.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "lualib.h" - - - -/* -** The whole module only makes sense with LUA_DEBUG on -*/ -#ifdef LUA_DEBUG - - -#define lua_pushintegral(L,i) lua_pushnumber(L, cast(lua_Number, (i))) - - -static lua_State *lua_state = NULL; - -int islocked = 0; - - -#define func_at(L,k) (L->ci->base+(k) - 1) - - -static void setnameval (lua_State *L, const char *name, int val) { - lua_pushstring(L, name); - lua_pushintegral(L, val); - lua_settable(L, -3); -} - - -/* -** {====================================================================== -** Controlled version for realloc. -** ======================================================================= -*/ - -#define MARK 0x55 /* 01010101 (a nice pattern) */ - -#ifndef EXTERNMEMCHECK -/* full memory check */ -#define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */ -#define MARKSIZE 16 /* size of marks after each block */ -#define blockhead(b) (cast(char *, b) - HEADER) -#define setsize(newblock, size) (*cast(size_t *, newblock) = size) -#define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b)))) -#define fillmem(mem,size) memset(mem, -MARK, size) -#else -/* external memory check: don't do it twice */ -#define HEADER 0 -#define MARKSIZE 0 -#define blockhead(b) (b) -#define setsize(newblock, size) /* empty */ -#define checkblocksize(b,size) (1) -#define fillmem(mem,size) /* empty */ -#endif - -unsigned long memdebug_numblocks = 0; -unsigned long memdebug_total = 0; -unsigned long memdebug_maxmem = 0; -unsigned long memdebug_memlimit = ULONG_MAX; - - -static void *checkblock (void *block, size_t size) { - void *b = blockhead(block); - int i; - for (i=0;i<MARKSIZE;i++) - lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */ - return b; -} - - -static void freeblock (void *block, size_t size) { - if (block) { - lua_assert(checkblocksize(block, size)); - block = checkblock(block, size); - fillmem(block, size+HEADER+MARKSIZE); /* erase block */ - free(block); /* free original block */ - memdebug_numblocks--; - memdebug_total -= size; - } -} - - -void *debug_realloc (void *block, size_t oldsize, size_t size) { - lua_assert(oldsize == 0 || checkblocksize(block, oldsize)); - /* ISO does not specify what realloc(NULL, 0) does */ - lua_assert(block != NULL || size > 0); - if (size == 0) { - freeblock(block, oldsize); - return NULL; - } - else if (size > oldsize && memdebug_total+size-oldsize > memdebug_memlimit) - return NULL; /* to test memory allocation errors */ - else { - void *newblock; - int i; - size_t realsize = HEADER+size+MARKSIZE; - size_t commonsize = (oldsize < size) ? oldsize : size; - if (realsize < size) return NULL; /* overflow! */ - newblock = malloc(realsize); /* alloc a new block */ - if (newblock == NULL) return NULL; - if (block) { - memcpy(cast(char *, newblock)+HEADER, block, commonsize); - freeblock(block, oldsize); /* erase (and check) old copy */ - } - /* initialize new part of the block with something `weird' */ - fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize); - memdebug_total += size; - if (memdebug_total > memdebug_maxmem) - memdebug_maxmem = memdebug_total; - memdebug_numblocks++; - setsize(newblock, size); - for (i=0;i<MARKSIZE;i++) - *(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i); - return cast(char *, newblock)+HEADER; - } -} - - -/* }====================================================================== */ - - - -/* -** {====================================================== -** Disassembler -** ======================================================= -*/ - - -static char *buildop (Proto *p, int pc, char *buff) { - Instruction i = p->code[pc]; - OpCode o = GET_OPCODE(i); - const char *name = luaP_opnames[o]; - int line = getline(p, pc); - sprintf(buff, "(%4d) %4d - ", line, pc); - switch (getOpMode(o)) { - case iABC: - sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name, - GETARG_A(i), GETARG_B(i), GETARG_C(i)); - break; - case iABx: - sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i)); - break; - case iAsBx: - sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i)); - break; - } - return buff; -} - - -#if 0 -void luaI_printcode (Proto *pt, int size) { - int pc; - for (pc=0; pc<size; pc++) { - char buff[100]; - printf("%s\n", buildop(pt, pc, buff)); - } - printf("-------\n"); -} -#endif - - -static int listcode (lua_State *L) { - int pc; - Proto *p; - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), - 1, "Lua function expected"); - p = clvalue(func_at(L, 1))->l.p; - lua_newtable(L); - setnameval(L, "maxstack", p->maxstacksize); - setnameval(L, "numparams", p->numparams); - for (pc=0; pc<p->sizecode; pc++) { - char buff[100]; - lua_pushintegral(L, pc+1); - lua_pushstring(L, buildop(p, pc, buff)); - lua_settable(L, -3); - } - return 1; -} - - -static int listk (lua_State *L) { - Proto *p; - int i; - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), - 1, "Lua function expected"); - p = clvalue(func_at(L, 1))->l.p; - lua_newtable(L); - for (i=0; i<p->sizek; i++) { - lua_pushintegral(L, i+1); - luaA_pushobject(L, p->k+i); - lua_settable(L, -3); - } - return 1; -} - - -static int listlocals (lua_State *L) { - Proto *p; - int pc = luaL_checkint(L, 2) - 1; - int i = 0; - const char *name; - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), - 1, "Lua function expected"); - p = clvalue(func_at(L, 1))->l.p; - while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) - lua_pushstring(L, name); - return i-1; -} - -/* }====================================================== */ - - - - -static int get_limits (lua_State *L) { - lua_newtable(L); - setnameval(L, "BITS_INT", BITS_INT); - setnameval(L, "LFPF", LFIELDS_PER_FLUSH); - setnameval(L, "MAXVARS", MAXVARS); - setnameval(L, "MAXPARAMS", MAXPARAMS); - setnameval(L, "MAXSTACK", MAXSTACK); - setnameval(L, "MAXUPVALUES", MAXUPVALUES); - return 1; -} - - -static int mem_query (lua_State *L) { - if (lua_isnone(L, 1)) { - lua_pushintegral(L, memdebug_total); - lua_pushintegral(L, memdebug_numblocks); - lua_pushintegral(L, memdebug_maxmem); - return 3; - } - else { - memdebug_memlimit = luaL_checkint(L, 1); - return 0; - } -} - - -static int hash_query (lua_State *L) { - if (lua_isnone(L, 2)) { - luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); - lua_pushintegral(L, tsvalue(func_at(L, 1))->tsv.hash); - } - else { - TObject *o = func_at(L, 1); - Table *t; - luaL_checktype(L, 2, LUA_TTABLE); - t = hvalue(func_at(L, 2)); - lua_pushintegral(L, luaH_mainposition(t, o) - t->node); - } - return 1; -} - - -static int stacklevel (lua_State *L) { - unsigned long a = 0; - lua_pushintegral(L, (int)(L->top - L->stack)); - lua_pushintegral(L, (int)(L->stack_last - L->stack)); - lua_pushintegral(L, (int)(L->ci - L->base_ci)); - lua_pushintegral(L, (int)(L->end_ci - L->base_ci)); - lua_pushintegral(L, (unsigned long)&a); - return 5; -} - - -static int table_query (lua_State *L) { - const Table *t; - int i = luaL_optint(L, 2, -1); - luaL_checktype(L, 1, LUA_TTABLE); - t = hvalue(func_at(L, 1)); - if (i == -1) { - lua_pushintegral(L, t->sizearray); - lua_pushintegral(L, sizenode(t)); - lua_pushintegral(L, t->firstfree - t->node); - } - else if (i < t->sizearray) { - lua_pushintegral(L, i); - luaA_pushobject(L, &t->array[i]); - lua_pushnil(L); - } - else if ((i -= t->sizearray) < sizenode(t)) { - if (!ttisnil(gval(gnode(t, i))) || - ttisnil(gkey(gnode(t, i))) || - ttisnumber(gkey(gnode(t, i)))) { - luaA_pushobject(L, gkey(gnode(t, i))); - } - else - lua_pushstring(L, "<undef>"); - luaA_pushobject(L, gval(gnode(t, i))); - if (t->node[i].next) - lua_pushintegral(L, t->node[i].next - t->node); - else - lua_pushnil(L); - } - return 3; -} - - -static int string_query (lua_State *L) { - stringtable *tb = &G(L)->strt; - int s = luaL_optint(L, 2, 0) - 1; - if (s==-1) { - lua_pushintegral(L ,tb->nuse); - lua_pushintegral(L ,tb->size); - return 2; - } - else if (s < tb->size) { - GCObject *ts; - int n = 0; - for (ts = tb->hash[s]; ts; ts = ts->gch.next) { - setsvalue2s(L->top, gcotots(ts)); - incr_top(L); - n++; - } - return n; - } - return 0; -} - - -static int tref (lua_State *L) { - int level = lua_gettop(L); - int lock = luaL_optint(L, 2, 1); - luaL_checkany(L, 1); - lua_pushvalue(L, 1); - lua_pushintegral(L, lua_ref(L, lock)); - assert(lua_gettop(L) == level+1); /* +1 for result */ - return 1; -} - -static int getref (lua_State *L) { - int level = lua_gettop(L); - lua_getref(L, luaL_checkint(L, 1)); - assert(lua_gettop(L) == level+1); - return 1; -} - -static int unref (lua_State *L) { - int level = lua_gettop(L); - lua_unref(L, luaL_checkint(L, 1)); - assert(lua_gettop(L) == level); - return 0; -} - -static int metatable (lua_State *L) { - luaL_checkany(L, 1); - if (lua_isnone(L, 2)) { - if (lua_getmetatable(L, 1) == 0) - lua_pushnil(L); - } - else { - lua_settop(L, 2); - luaL_checktype(L, 2, LUA_TTABLE); - lua_setmetatable(L, 1); - } - return 1; -} - - -static int upvalue (lua_State *L) { - int n = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TFUNCTION); - if (lua_isnone(L, 3)) { - const char *name = lua_getupvalue(L, 1, n); - if (name == NULL) return 0; - lua_pushstring(L, name); - return 2; - } - else { - const char *name = lua_setupvalue(L, 1, n); - lua_pushstring(L, name); - return 1; - } -} - - -static int newuserdata (lua_State *L) { - size_t size = luaL_checkint(L, 1); - char *p = cast(char *, lua_newuserdata(L, size)); - while (size--) *p++ = '\0'; - return 1; -} - - -static int pushuserdata (lua_State *L) { - lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1))); - return 1; -} - - -static int udataval (lua_State *L) { - lua_pushintegral(L, cast(int, lua_touserdata(L, 1))); - return 1; -} - - -static int doonnewstack (lua_State *L) { - lua_State *L1 = lua_newthread(L); - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - int status = luaL_loadbuffer(L1, s, l, s); - if (status == 0) - status = lua_pcall(L1, 0, 0, 0); - lua_pushintegral(L, status); - return 1; -} - - -static int s2d (lua_State *L) { - lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1))); - return 1; -} - -static int d2s (lua_State *L) { - double d = luaL_checknumber(L, 1); - lua_pushlstring(L, cast(char *, &d), sizeof(d)); - return 1; -} - - -static int newstate (lua_State *L) { - lua_State *L1 = lua_open(); - if (L1) { - lua_userstateopen(L1); /* init lock */ - lua_pushintegral(L, (unsigned long)L1); - } - else - lua_pushnil(L); - return 1; -} - - -static int loadlib (lua_State *L) { - static const luaL_reg libs[] = { - {"mathlibopen", luaopen_math}, - {"strlibopen", luaopen_string}, - {"iolibopen", luaopen_io}, - {"tablibopen", luaopen_table}, - {"dblibopen", luaopen_debug}, - {"baselibopen", luaopen_base}, - {NULL, NULL} - }; - lua_State *L1 = cast(lua_State *, - cast(unsigned long, luaL_checknumber(L, 1))); - lua_pushvalue(L1, LUA_GLOBALSINDEX); - luaL_openlib(L1, NULL, libs, 0); - return 0; -} - -static int closestate (lua_State *L) { - lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1))); - lua_close(L1); - lua_unlock(L); /* close cannot unlock that */ - return 0; -} - -static int doremote (lua_State *L) { - lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1))); - size_t lcode; - const char *code = luaL_checklstring(L, 2, &lcode); - int status; - lua_settop(L1, 0); - status = luaL_loadbuffer(L1, code, lcode, code); - if (status == 0) - status = lua_pcall(L1, 0, LUA_MULTRET, 0); - if (status != 0) { - lua_pushnil(L); - lua_pushintegral(L, status); - lua_pushstring(L, lua_tostring(L1, -1)); - return 3; - } - else { - int i = 0; - while (!lua_isnone(L1, ++i)) - lua_pushstring(L, lua_tostring(L1, i)); - lua_pop(L1, i-1); - return i-1; - } -} - - -static int log2_aux (lua_State *L) { - lua_pushintegral(L, luaO_log2(luaL_checkint(L, 1))); - return 1; -} - -static int int2fb_aux (lua_State *L) { - int b = luaO_int2fb(luaL_checkint(L, 1)); - lua_pushintegral(L, b); - lua_pushintegral(L, fb2int(b)); - return 2; -} - - -static int test_do (lua_State *L) { - const char *p = luaL_checkstring(L, 1); - if (*p == '@') - lua_dofile(L, p+1); - else - lua_dostring(L, p); - return lua_gettop(L); -} - - - -/* -** {====================================================== -** function to test the API with C. It interprets a kind of assembler -** language with calls to the API, so the test can be driven by Lua code -** ======================================================= -*/ - -static const char *const delimits = " \t\n,;"; - -static void skip (const char **pc) { - while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; -} - -static int getnum_aux (lua_State *L, const char **pc) { - int res = 0; - int sig = 1; - skip(pc); - if (**pc == '.') { - res = cast(int, lua_tonumber(L, -1)); - lua_pop(L, 1); - (*pc)++; - return res; - } - else if (**pc == '-') { - sig = -1; - (*pc)++; - } - while (isdigit(cast(int, **pc))) res = res*10 + (*(*pc)++) - '0'; - return sig*res; -} - -static const char *getname_aux (char *buff, const char **pc) { - int i = 0; - skip(pc); - while (**pc != '\0' && !strchr(delimits, **pc)) - buff[i++] = *(*pc)++; - buff[i] = '\0'; - return buff; -} - - -#define EQ(s1) (strcmp(s1, inst) == 0) - -#define getnum (getnum_aux(L, &pc)) -#define getname (getname_aux(buff, &pc)) - - -static int testC (lua_State *L) { - char buff[30]; - const char *pc = luaL_checkstring(L, 1); - for (;;) { - const char *inst = getname; - if EQ("") return 0; - else if EQ("isnumber") { - lua_pushintegral(L, lua_isnumber(L, getnum)); - } - else if EQ("isstring") { - lua_pushintegral(L, lua_isstring(L, getnum)); - } - else if EQ("istable") { - lua_pushintegral(L, lua_istable(L, getnum)); - } - else if EQ("iscfunction") { - lua_pushintegral(L, lua_iscfunction(L, getnum)); - } - else if EQ("isfunction") { - lua_pushintegral(L, lua_isfunction(L, getnum)); - } - else if EQ("isuserdata") { - lua_pushintegral(L, lua_isuserdata(L, getnum)); - } - else if EQ("isudataval") { - lua_pushintegral(L, lua_islightuserdata(L, getnum)); - } - else if EQ("isnil") { - lua_pushintegral(L, lua_isnil(L, getnum)); - } - else if EQ("isnull") { - lua_pushintegral(L, lua_isnone(L, getnum)); - } - else if EQ("tonumber") { - lua_pushnumber(L, lua_tonumber(L, getnum)); - } - else if EQ("tostring") { - const char *s = lua_tostring(L, getnum); - lua_pushstring(L, s); - } - else if EQ("strlen") { - lua_pushintegral(L, lua_strlen(L, getnum)); - } - else if EQ("tocfunction") { - lua_pushcfunction(L, lua_tocfunction(L, getnum)); - } - else if EQ("return") { - return getnum; - } - else if EQ("gettop") { - lua_pushintegral(L, lua_gettop(L)); - } - else if EQ("settop") { - lua_settop(L, getnum); - } - else if EQ("pop") { - lua_pop(L, getnum); - } - else if EQ("pushnum") { - lua_pushintegral(L, getnum); - } - else if EQ("pushnil") { - lua_pushnil(L); - } - else if EQ("pushbool") { - lua_pushboolean(L, getnum); - } - else if EQ("tobool") { - lua_pushintegral(L, lua_toboolean(L, getnum)); - } - else if EQ("pushvalue") { - lua_pushvalue(L, getnum); - } - else if EQ("pushcclosure") { - lua_pushcclosure(L, testC, getnum); - } - else if EQ("pushupvalues") { - lua_pushupvalues(L); - } - else if EQ("remove") { - lua_remove(L, getnum); - } - else if EQ("insert") { - lua_insert(L, getnum); - } - else if EQ("replace") { - lua_replace(L, getnum); - } - else if EQ("gettable") { - lua_gettable(L, getnum); - } - else if EQ("settable") { - lua_settable(L, getnum); - } - else if EQ("next") { - lua_next(L, -2); - } - else if EQ("concat") { - lua_concat(L, getnum); - } - else if EQ("lessthan") { - int a = getnum; - lua_pushboolean(L, lua_lessthan(L, a, getnum)); - } - else if EQ("equal") { - int a = getnum; - lua_pushboolean(L, lua_equal(L, a, getnum)); - } - else if EQ("rawcall") { - int narg = getnum; - int nres = getnum; - lua_call(L, narg, nres); - } - else if EQ("call") { - int narg = getnum; - int nres = getnum; - lua_pcall(L, narg, nres, 0); - } - else if EQ("loadstring") { - size_t sl; - const char *s = luaL_checklstring(L, getnum, &sl); - luaL_loadbuffer(L, s, sl, s); - } - else if EQ("loadfile") { - luaL_loadfile(L, luaL_checkstring(L, getnum)); - } - else if EQ("setmetatable") { - lua_setmetatable(L, getnum); - } - else if EQ("getmetatable") { - if (lua_getmetatable(L, getnum) == 0) - lua_pushnil(L); - } - else if EQ("type") { - lua_pushstring(L, lua_typename(L, lua_type(L, getnum))); - } - else if EQ("getn") { - int i = getnum; - lua_pushintegral(L, luaL_getn(L, i)); - } - else if EQ("setn") { - int i = getnum; - int n = cast(int, lua_tonumber(L, -1)); - luaL_setn(L, i, n); - lua_pop(L, 1); - } - else luaL_error(L, "unknown instruction %s", buff); - } - return 0; -} - -/* }====================================================== */ - - -/* -** {====================================================== -** tests for yield inside hooks -** ======================================================= -*/ - -static void yieldf (lua_State *L, lua_Debug *ar) { - lua_yield(L, 0); -} - -static int setyhook (lua_State *L) { - if (lua_isnoneornil(L, 1)) - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ - else { - const char *smask = luaL_checkstring(L, 1); - int count = luaL_optint(L, 2, 0); - int mask = 0; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - lua_sethook(L, yieldf, mask, count); - } - return 0; -} - - -static int coresume (lua_State *L) { - int status; - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); - status = lua_resume(co, 0); - if (status != 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - return 1; - } -} - -/* }====================================================== */ - - - -static const struct luaL_reg tests_funcs[] = { - {"hash", hash_query}, - {"limits", get_limits}, - {"listcode", listcode}, - {"listk", listk}, - {"listlocals", listlocals}, - {"loadlib", loadlib}, - {"stacklevel", stacklevel}, - {"querystr", string_query}, - {"querytab", table_query}, - {"doit", test_do}, - {"testC", testC}, - {"ref", tref}, - {"getref", getref}, - {"unref", unref}, - {"d2s", d2s}, - {"s2d", s2d}, - {"metatable", metatable}, - {"upvalue", upvalue}, - {"newuserdata", newuserdata}, - {"pushuserdata", pushuserdata}, - {"udataval", udataval}, - {"doonnewstack", doonnewstack}, - {"newstate", newstate}, - {"closestate", closestate}, - {"doremote", doremote}, - {"log2", log2_aux}, - {"int2fb", int2fb_aux}, - {"totalmem", mem_query}, - {"resume", coresume}, - {"setyhook", setyhook}, - {NULL, NULL} -}; - - -static void fim (void) { - if (!islocked) - lua_close(lua_state); - lua_assert(memdebug_numblocks == 0); - lua_assert(memdebug_total == 0); -} - - -static int l_panic (lua_State *L) { - UNUSED(L); - fprintf(stderr, "unable to recover; exiting\n"); - return 0; -} - - -int luaB_opentests (lua_State *L) { - lua_atpanic(L, l_panic); - lua_userstateopen(L); /* init lock */ - lua_state = L; /* keep first state to be opened */ - luaL_openlib(L, "T", tests_funcs, 0); - atexit(fim); - return 0; -} - - -#undef main -int main (int argc, char *argv[]) { - char *limit = getenv("MEMLIMIT"); - if (limit) - memdebug_memlimit = strtoul(limit, NULL, 10); - l_main(argc, argv); - return 0; -} - -#endif +/*
+** $Id: ltests.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Internal Module for Debugging of the Lua Implementation
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ltests_c
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lauxlib.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lualib.h"
+
+
+
+/*
+** The whole module only makes sense with LUA_DEBUG on
+*/
+#ifdef LUA_DEBUG
+
+
+#define lua_pushintegral(L,i) lua_pushnumber(L, cast(lua_Number, (i)))
+
+
+static lua_State *lua_state = NULL;
+
+int islocked = 0;
+
+
+#define func_at(L,k) (L->ci->base+(k) - 1)
+
+
+static void setnameval (lua_State *L, const char *name, int val) {
+ lua_pushstring(L, name);
+ lua_pushintegral(L, val);
+ lua_settable(L, -3);
+}
+
+
+/*
+** {======================================================================
+** Controlled version for realloc.
+** =======================================================================
+*/
+
+#define MARK 0x55 /* 01010101 (a nice pattern) */
+
+#ifndef EXTERNMEMCHECK
+/* full memory check */
+#define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */
+#define MARKSIZE 16 /* size of marks after each block */
+#define blockhead(b) (cast(char *, b) - HEADER)
+#define setsize(newblock, size) (*cast(size_t *, newblock) = size)
+#define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b))))
+#define fillmem(mem,size) memset(mem, -MARK, size)
+#else
+/* external memory check: don't do it twice */
+#define HEADER 0
+#define MARKSIZE 0
+#define blockhead(b) (b)
+#define setsize(newblock, size) /* empty */
+#define checkblocksize(b,size) (1)
+#define fillmem(mem,size) /* empty */
+#endif
+
+unsigned long memdebug_numblocks = 0;
+unsigned long memdebug_total = 0;
+unsigned long memdebug_maxmem = 0;
+unsigned long memdebug_memlimit = ULONG_MAX;
+
+
+static void *checkblock (void *block, size_t size) {
+ void *b = blockhead(block);
+ int i;
+ for (i=0;i<MARKSIZE;i++)
+ lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */
+ return b;
+}
+
+
+static void freeblock (void *block, size_t size) {
+ if (block) {
+ lua_assert(checkblocksize(block, size));
+ block = checkblock(block, size);
+ fillmem(block, size+HEADER+MARKSIZE); /* erase block */
+ free(block); /* free original block */
+ memdebug_numblocks--;
+ memdebug_total -= size;
+ }
+}
+
+
+void *debug_realloc (void *block, size_t oldsize, size_t size) {
+ lua_assert(oldsize == 0 || checkblocksize(block, oldsize));
+ /* ISO does not specify what realloc(NULL, 0) does */
+ lua_assert(block != NULL || size > 0);
+ if (size == 0) {
+ freeblock(block, oldsize);
+ return NULL;
+ }
+ else if (size > oldsize && memdebug_total+size-oldsize > memdebug_memlimit)
+ return NULL; /* to test memory allocation errors */
+ else {
+ void *newblock;
+ int i;
+ size_t realsize = HEADER+size+MARKSIZE;
+ size_t commonsize = (oldsize < size) ? oldsize : size;
+ if (realsize < size) return NULL; /* overflow! */
+ newblock = malloc(realsize); /* alloc a new block */
+ if (newblock == NULL) return NULL;
+ if (block) {
+ memcpy(cast(char *, newblock)+HEADER, block, commonsize);
+ freeblock(block, oldsize); /* erase (and check) old copy */
+ }
+ /* initialize new part of the block with something `weird' */
+ fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize);
+ memdebug_total += size;
+ if (memdebug_total > memdebug_maxmem)
+ memdebug_maxmem = memdebug_total;
+ memdebug_numblocks++;
+ setsize(newblock, size);
+ for (i=0;i<MARKSIZE;i++)
+ *(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i);
+ return cast(char *, newblock)+HEADER;
+ }
+}
+
+
+/* }====================================================================== */
+
+
+
+/*
+** {======================================================
+** Disassembler
+** =======================================================
+*/
+
+
+static char *buildop (Proto *p, int pc, char *buff) {
+ Instruction i = p->code[pc];
+ OpCode o = GET_OPCODE(i);
+ const char *name = luaP_opnames[o];
+ int line = getline(p, pc);
+ sprintf(buff, "(%4d) %4d - ", line, pc);
+ switch (getOpMode(o)) {
+ case iABC:
+ sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name,
+ GETARG_A(i), GETARG_B(i), GETARG_C(i));
+ break;
+ case iABx:
+ sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i));
+ break;
+ case iAsBx:
+ sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i));
+ break;
+ }
+ return buff;
+}
+
+
+#if 0
+void luaI_printcode (Proto *pt, int size) {
+ int pc;
+ for (pc=0; pc<size; pc++) {
+ char buff[100];
+ printf("%s\n", buildop(pt, pc, buff));
+ }
+ printf("-------\n");
+}
+#endif
+
+
+static int listcode (lua_State *L) {
+ int pc;
+ Proto *p;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(func_at(L, 1))->l.p;
+ lua_newtable(L);
+ setnameval(L, "maxstack", p->maxstacksize);
+ setnameval(L, "numparams", p->numparams);
+ for (pc=0; pc<p->sizecode; pc++) {
+ char buff[100];
+ lua_pushintegral(L, pc+1);
+ lua_pushstring(L, buildop(p, pc, buff));
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+
+static int listk (lua_State *L) {
+ Proto *p;
+ int i;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(func_at(L, 1))->l.p;
+ lua_newtable(L);
+ for (i=0; i<p->sizek; i++) {
+ lua_pushintegral(L, i+1);
+ luaA_pushobject(L, p->k+i);
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+
+static int listlocals (lua_State *L) {
+ Proto *p;
+ int pc = luaL_checkint(L, 2) - 1;
+ int i = 0;
+ const char *name;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(func_at(L, 1))->l.p;
+ while ((name = luaF_getlocalname(p, ++i, pc)) != NULL)
+ lua_pushstring(L, name);
+ return i-1;
+}
+
+/* }====================================================== */
+
+
+
+
+static int get_limits (lua_State *L) {
+ lua_newtable(L);
+ setnameval(L, "BITS_INT", BITS_INT);
+ setnameval(L, "LFPF", LFIELDS_PER_FLUSH);
+ setnameval(L, "MAXVARS", MAXVARS);
+ setnameval(L, "MAXPARAMS", MAXPARAMS);
+ setnameval(L, "MAXSTACK", MAXSTACK);
+ setnameval(L, "MAXUPVALUES", MAXUPVALUES);
+ return 1;
+}
+
+
+static int mem_query (lua_State *L) {
+ if (lua_isnone(L, 1)) {
+ lua_pushintegral(L, memdebug_total);
+ lua_pushintegral(L, memdebug_numblocks);
+ lua_pushintegral(L, memdebug_maxmem);
+ return 3;
+ }
+ else {
+ memdebug_memlimit = luaL_checkint(L, 1);
+ return 0;
+ }
+}
+
+
+static int hash_query (lua_State *L) {
+ if (lua_isnone(L, 2)) {
+ luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
+ lua_pushintegral(L, tsvalue(func_at(L, 1))->tsv.hash);
+ }
+ else {
+ TObject *o = func_at(L, 1);
+ Table *t;
+ luaL_checktype(L, 2, LUA_TTABLE);
+ t = hvalue(func_at(L, 2));
+ lua_pushintegral(L, luaH_mainposition(t, o) - t->node);
+ }
+ return 1;
+}
+
+
+static int stacklevel (lua_State *L) {
+ unsigned long a = 0;
+ lua_pushintegral(L, (int)(L->top - L->stack));
+ lua_pushintegral(L, (int)(L->stack_last - L->stack));
+ lua_pushintegral(L, (int)(L->ci - L->base_ci));
+ lua_pushintegral(L, (int)(L->end_ci - L->base_ci));
+ lua_pushintegral(L, (unsigned long)&a);
+ return 5;
+}
+
+
+static int table_query (lua_State *L) {
+ const Table *t;
+ int i = luaL_optint(L, 2, -1);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ t = hvalue(func_at(L, 1));
+ if (i == -1) {
+ lua_pushintegral(L, t->sizearray);
+ lua_pushintegral(L, sizenode(t));
+ lua_pushintegral(L, t->firstfree - t->node);
+ }
+ else if (i < t->sizearray) {
+ lua_pushintegral(L, i);
+ luaA_pushobject(L, &t->array[i]);
+ lua_pushnil(L);
+ }
+ else if ((i -= t->sizearray) < sizenode(t)) {
+ if (!ttisnil(gval(gnode(t, i))) ||
+ ttisnil(gkey(gnode(t, i))) ||
+ ttisnumber(gkey(gnode(t, i)))) {
+ luaA_pushobject(L, gkey(gnode(t, i)));
+ }
+ else
+ lua_pushstring(L, "<undef>");
+ luaA_pushobject(L, gval(gnode(t, i)));
+ if (t->node[i].next)
+ lua_pushintegral(L, t->node[i].next - t->node);
+ else
+ lua_pushnil(L);
+ }
+ return 3;
+}
+
+
+static int string_query (lua_State *L) {
+ stringtable *tb = &G(L)->strt;
+ int s = luaL_optint(L, 2, 0) - 1;
+ if (s==-1) {
+ lua_pushintegral(L ,tb->nuse);
+ lua_pushintegral(L ,tb->size);
+ return 2;
+ }
+ else if (s < tb->size) {
+ GCObject *ts;
+ int n = 0;
+ for (ts = tb->hash[s]; ts; ts = ts->gch.next) {
+ setsvalue2s(L->top, gcotots(ts));
+ incr_top(L);
+ n++;
+ }
+ return n;
+ }
+ return 0;
+}
+
+
+static int tref (lua_State *L) {
+ int level = lua_gettop(L);
+ int lock = luaL_optint(L, 2, 1);
+ luaL_checkany(L, 1);
+ lua_pushvalue(L, 1);
+ lua_pushintegral(L, lua_ref(L, lock));
+ assert(lua_gettop(L) == level+1); /* +1 for result */
+ return 1;
+}
+
+static int getref (lua_State *L) {
+ int level = lua_gettop(L);
+ lua_getref(L, luaL_checkint(L, 1));
+ assert(lua_gettop(L) == level+1);
+ return 1;
+}
+
+static int unref (lua_State *L) {
+ int level = lua_gettop(L);
+ lua_unref(L, luaL_checkint(L, 1));
+ assert(lua_gettop(L) == level);
+ return 0;
+}
+
+static int metatable (lua_State *L) {
+ luaL_checkany(L, 1);
+ if (lua_isnone(L, 2)) {
+ if (lua_getmetatable(L, 1) == 0)
+ lua_pushnil(L);
+ }
+ else {
+ lua_settop(L, 2);
+ luaL_checktype(L, 2, LUA_TTABLE);
+ lua_setmetatable(L, 1);
+ }
+ return 1;
+}
+
+
+static int upvalue (lua_State *L) {
+ int n = luaL_checkint(L, 2);
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ if (lua_isnone(L, 3)) {
+ const char *name = lua_getupvalue(L, 1, n);
+ if (name == NULL) return 0;
+ lua_pushstring(L, name);
+ return 2;
+ }
+ else {
+ const char *name = lua_setupvalue(L, 1, n);
+ lua_pushstring(L, name);
+ return 1;
+ }
+}
+
+
+static int newuserdata (lua_State *L) {
+ size_t size = luaL_checkint(L, 1);
+ char *p = cast(char *, lua_newuserdata(L, size));
+ while (size--) *p++ = '\0';
+ return 1;
+}
+
+
+static int pushuserdata (lua_State *L) {
+ lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1)));
+ return 1;
+}
+
+
+static int udataval (lua_State *L) {
+ lua_pushintegral(L, cast(int, lua_touserdata(L, 1)));
+ return 1;
+}
+
+
+static int doonnewstack (lua_State *L) {
+ lua_State *L1 = lua_newthread(L);
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ int status = luaL_loadbuffer(L1, s, l, s);
+ if (status == 0)
+ status = lua_pcall(L1, 0, 0, 0);
+ lua_pushintegral(L, status);
+ return 1;
+}
+
+
+static int s2d (lua_State *L) {
+ lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1)));
+ return 1;
+}
+
+static int d2s (lua_State *L) {
+ double d = luaL_checknumber(L, 1);
+ lua_pushlstring(L, cast(char *, &d), sizeof(d));
+ return 1;
+}
+
+
+static int newstate (lua_State *L) {
+ lua_State *L1 = lua_open();
+ if (L1) {
+ lua_userstateopen(L1); /* init lock */
+ lua_pushintegral(L, (unsigned long)L1);
+ }
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+
+static int loadlib (lua_State *L) {
+ static const luaL_reg libs[] = {
+ {"mathlibopen", luaopen_math},
+ {"strlibopen", luaopen_string},
+ {"iolibopen", luaopen_io},
+ {"tablibopen", luaopen_table},
+ {"dblibopen", luaopen_debug},
+ {"baselibopen", luaopen_base},
+ {NULL, NULL}
+ };
+ lua_State *L1 = cast(lua_State *,
+ cast(unsigned long, luaL_checknumber(L, 1)));
+ lua_pushvalue(L1, LUA_GLOBALSINDEX);
+ luaL_openlib(L1, NULL, libs, 0);
+ return 0;
+}
+
+static int closestate (lua_State *L) {
+ lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1)));
+ lua_close(L1);
+ lua_unlock(L); /* close cannot unlock that */
+ return 0;
+}
+
+static int doremote (lua_State *L) {
+ lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1)));
+ size_t lcode;
+ const char *code = luaL_checklstring(L, 2, &lcode);
+ int status;
+ lua_settop(L1, 0);
+ status = luaL_loadbuffer(L1, code, lcode, code);
+ if (status == 0)
+ status = lua_pcall(L1, 0, LUA_MULTRET, 0);
+ if (status != 0) {
+ lua_pushnil(L);
+ lua_pushintegral(L, status);
+ lua_pushstring(L, lua_tostring(L1, -1));
+ return 3;
+ }
+ else {
+ int i = 0;
+ while (!lua_isnone(L1, ++i))
+ lua_pushstring(L, lua_tostring(L1, i));
+ lua_pop(L1, i-1);
+ return i-1;
+ }
+}
+
+
+static int log2_aux (lua_State *L) {
+ lua_pushintegral(L, luaO_log2(luaL_checkint(L, 1)));
+ return 1;
+}
+
+static int int2fb_aux (lua_State *L) {
+ int b = luaO_int2fb(luaL_checkint(L, 1));
+ lua_pushintegral(L, b);
+ lua_pushintegral(L, fb2int(b));
+ return 2;
+}
+
+
+static int test_do (lua_State *L) {
+ const char *p = luaL_checkstring(L, 1);
+ if (*p == '@')
+ lua_dofile(L, p+1);
+ else
+ lua_dostring(L, p);
+ return lua_gettop(L);
+}
+
+
+
+/*
+** {======================================================
+** function to test the API with C. It interprets a kind of assembler
+** language with calls to the API, so the test can be driven by Lua code
+** =======================================================
+*/
+
+static const char *const delimits = " \t\n,;";
+
+static void skip (const char **pc) {
+ while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
+}
+
+static int getnum_aux (lua_State *L, const char **pc) {
+ int res = 0;
+ int sig = 1;
+ skip(pc);
+ if (**pc == '.') {
+ res = cast(int, lua_tonumber(L, -1));
+ lua_pop(L, 1);
+ (*pc)++;
+ return res;
+ }
+ else if (**pc == '-') {
+ sig = -1;
+ (*pc)++;
+ }
+ while (isdigit(cast(int, **pc))) res = res*10 + (*(*pc)++) - '0';
+ return sig*res;
+}
+
+static const char *getname_aux (char *buff, const char **pc) {
+ int i = 0;
+ skip(pc);
+ while (**pc != '\0' && !strchr(delimits, **pc))
+ buff[i++] = *(*pc)++;
+ buff[i] = '\0';
+ return buff;
+}
+
+
+#define EQ(s1) (strcmp(s1, inst) == 0)
+
+#define getnum (getnum_aux(L, &pc))
+#define getname (getname_aux(buff, &pc))
+
+
+static int testC (lua_State *L) {
+ char buff[30];
+ const char *pc = luaL_checkstring(L, 1);
+ for (;;) {
+ const char *inst = getname;
+ if EQ("") return 0;
+ else if EQ("isnumber") {
+ lua_pushintegral(L, lua_isnumber(L, getnum));
+ }
+ else if EQ("isstring") {
+ lua_pushintegral(L, lua_isstring(L, getnum));
+ }
+ else if EQ("istable") {
+ lua_pushintegral(L, lua_istable(L, getnum));
+ }
+ else if EQ("iscfunction") {
+ lua_pushintegral(L, lua_iscfunction(L, getnum));
+ }
+ else if EQ("isfunction") {
+ lua_pushintegral(L, lua_isfunction(L, getnum));
+ }
+ else if EQ("isuserdata") {
+ lua_pushintegral(L, lua_isuserdata(L, getnum));
+ }
+ else if EQ("isudataval") {
+ lua_pushintegral(L, lua_islightuserdata(L, getnum));
+ }
+ else if EQ("isnil") {
+ lua_pushintegral(L, lua_isnil(L, getnum));
+ }
+ else if EQ("isnull") {
+ lua_pushintegral(L, lua_isnone(L, getnum));
+ }
+ else if EQ("tonumber") {
+ lua_pushnumber(L, lua_tonumber(L, getnum));
+ }
+ else if EQ("tostring") {
+ const char *s = lua_tostring(L, getnum);
+ lua_pushstring(L, s);
+ }
+ else if EQ("strlen") {
+ lua_pushintegral(L, lua_strlen(L, getnum));
+ }
+ else if EQ("tocfunction") {
+ lua_pushcfunction(L, lua_tocfunction(L, getnum));
+ }
+ else if EQ("return") {
+ return getnum;
+ }
+ else if EQ("gettop") {
+ lua_pushintegral(L, lua_gettop(L));
+ }
+ else if EQ("settop") {
+ lua_settop(L, getnum);
+ }
+ else if EQ("pop") {
+ lua_pop(L, getnum);
+ }
+ else if EQ("pushnum") {
+ lua_pushintegral(L, getnum);
+ }
+ else if EQ("pushnil") {
+ lua_pushnil(L);
+ }
+ else if EQ("pushbool") {
+ lua_pushboolean(L, getnum);
+ }
+ else if EQ("tobool") {
+ lua_pushintegral(L, lua_toboolean(L, getnum));
+ }
+ else if EQ("pushvalue") {
+ lua_pushvalue(L, getnum);
+ }
+ else if EQ("pushcclosure") {
+ lua_pushcclosure(L, testC, getnum);
+ }
+ else if EQ("pushupvalues") {
+ lua_pushupvalues(L);
+ }
+ else if EQ("remove") {
+ lua_remove(L, getnum);
+ }
+ else if EQ("insert") {
+ lua_insert(L, getnum);
+ }
+ else if EQ("replace") {
+ lua_replace(L, getnum);
+ }
+ else if EQ("gettable") {
+ lua_gettable(L, getnum);
+ }
+ else if EQ("settable") {
+ lua_settable(L, getnum);
+ }
+ else if EQ("next") {
+ lua_next(L, -2);
+ }
+ else if EQ("concat") {
+ lua_concat(L, getnum);
+ }
+ else if EQ("lessthan") {
+ int a = getnum;
+ lua_pushboolean(L, lua_lessthan(L, a, getnum));
+ }
+ else if EQ("equal") {
+ int a = getnum;
+ lua_pushboolean(L, lua_equal(L, a, getnum));
+ }
+ else if EQ("rawcall") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_call(L, narg, nres);
+ }
+ else if EQ("call") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_pcall(L, narg, nres, 0);
+ }
+ else if EQ("loadstring") {
+ size_t sl;
+ const char *s = luaL_checklstring(L, getnum, &sl);
+ luaL_loadbuffer(L, s, sl, s);
+ }
+ else if EQ("loadfile") {
+ luaL_loadfile(L, luaL_checkstring(L, getnum));
+ }
+ else if EQ("setmetatable") {
+ lua_setmetatable(L, getnum);
+ }
+ else if EQ("getmetatable") {
+ if (lua_getmetatable(L, getnum) == 0)
+ lua_pushnil(L);
+ }
+ else if EQ("type") {
+ lua_pushstring(L, lua_typename(L, lua_type(L, getnum)));
+ }
+ else if EQ("getn") {
+ int i = getnum;
+ lua_pushintegral(L, luaL_getn(L, i));
+ }
+ else if EQ("setn") {
+ int i = getnum;
+ int n = cast(int, lua_tonumber(L, -1));
+ luaL_setn(L, i, n);
+ lua_pop(L, 1);
+ }
+ else luaL_error(L, "unknown instruction %s", buff);
+ }
+ return 0;
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** tests for yield inside hooks
+** =======================================================
+*/
+
+static void yieldf (lua_State *L, lua_Debug *ar) {
+ lua_yield(L, 0);
+}
+
+static int setyhook (lua_State *L) {
+ if (lua_isnoneornil(L, 1))
+ lua_sethook(L, NULL, 0, 0); /* turn off hooks */
+ else {
+ const char *smask = luaL_checkstring(L, 1);
+ int count = luaL_optint(L, 2, 0);
+ int mask = 0;
+ if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
+ if (count > 0) mask |= LUA_MASKCOUNT;
+ lua_sethook(L, yieldf, mask, count);
+ }
+ return 0;
+}
+
+
+static int coresume (lua_State *L) {
+ int status;
+ lua_State *co = lua_tothread(L, 1);
+ luaL_argcheck(L, co, 1, "coroutine expected");
+ status = lua_resume(co, 0);
+ if (status != 0) {
+ lua_pushboolean(L, 0);
+ lua_insert(L, -2);
+ return 2; /* return false + error message */
+ }
+ else {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+}
+
+/* }====================================================== */
+
+
+
+static const struct luaL_reg tests_funcs[] = {
+ {"hash", hash_query},
+ {"limits", get_limits},
+ {"listcode", listcode},
+ {"listk", listk},
+ {"listlocals", listlocals},
+ {"loadlib", loadlib},
+ {"stacklevel", stacklevel},
+ {"querystr", string_query},
+ {"querytab", table_query},
+ {"doit", test_do},
+ {"testC", testC},
+ {"ref", tref},
+ {"getref", getref},
+ {"unref", unref},
+ {"d2s", d2s},
+ {"s2d", s2d},
+ {"metatable", metatable},
+ {"upvalue", upvalue},
+ {"newuserdata", newuserdata},
+ {"pushuserdata", pushuserdata},
+ {"udataval", udataval},
+ {"doonnewstack", doonnewstack},
+ {"newstate", newstate},
+ {"closestate", closestate},
+ {"doremote", doremote},
+ {"log2", log2_aux},
+ {"int2fb", int2fb_aux},
+ {"totalmem", mem_query},
+ {"resume", coresume},
+ {"setyhook", setyhook},
+ {NULL, NULL}
+};
+
+
+static void fim (void) {
+ if (!islocked)
+ lua_close(lua_state);
+ lua_assert(memdebug_numblocks == 0);
+ lua_assert(memdebug_total == 0);
+}
+
+
+static int l_panic (lua_State *L) {
+ UNUSED(L);
+ fprintf(stderr, "unable to recover; exiting\n");
+ return 0;
+}
+
+
+int luaB_opentests (lua_State *L) {
+ lua_atpanic(L, l_panic);
+ lua_userstateopen(L); /* init lock */
+ lua_state = L; /* keep first state to be opened */
+ luaL_openlib(L, "T", tests_funcs, 0);
+ atexit(fim);
+ return 0;
+}
+
+
+#undef main
+int main (int argc, char *argv[]) {
+ char *limit = getenv("MEMLIMIT");
+ if (limit)
+ memdebug_memlimit = strtoul(limit, NULL, 10);
+ l_main(argc, argv);
+ return 0;
+}
+
+#endif
diff --git a/lib/lua/src/ltm.c b/lib/lua/src/ltm.c index 9ffe7b2..204bf46 100644 --- a/lib/lua/src/ltm.c +++ b/lib/lua/src/ltm.c @@ -1,70 +1,70 @@ -/* -** $Id: ltm.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** Tag methods -** See Copyright Notice in lua.h -*/ - - -#include <string.h> - -#define ltm_c - -#include "lua.h" - -#include "lobject.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" - - - -const char *const luaT_typenames[] = { - "nil", "boolean", "userdata", "number", - "string", "table", "function", "userdata", "thread" -}; - - -void luaT_init (lua_State *L) { - static const char *const luaT_eventname[] = { /* ORDER TM */ - "__index", "__newindex", - "__gc", "__mode", "__eq", - "__add", "__sub", "__mul", "__div", - "__pow", "__unm", "__lt", "__le", - "__concat", "__call" - }; - int i; - for (i=0; i<TM_N; i++) { - G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]); - luaS_fix(G(L)->tmname[i]); /* never collect these names */ - } -} - - -/* -** function to be used with macro "fasttm": optimized for absence of -** tag methods -*/ -const TObject *luaT_gettm (Table *events, TMS event, TString *ename) { - const TObject *tm = luaH_getstr(events, ename); - lua_assert(event <= TM_EQ); - if (ttisnil(tm)) { /* no tag method? */ - events->flags |= cast(lu_byte, 1u<<event); /* cache this fact */ - return NULL; - } - else return tm; -} - - -const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event) { - TString *ename = G(L)->tmname[event]; - switch (ttype(o)) { - case LUA_TTABLE: - return luaH_getstr(hvalue(o)->metatable, ename); - case LUA_TUSERDATA: - return luaH_getstr(uvalue(o)->uv.metatable, ename); - default: - return &luaO_nilobject; - } -} - +/*
+** $Id: ltm.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** Tag methods
+** See Copyright Notice in lua.h
+*/
+
+
+#include <string.h>
+
+#define ltm_c
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+
+const char *const luaT_typenames[] = {
+ "nil", "boolean", "userdata", "number",
+ "string", "table", "function", "userdata", "thread"
+};
+
+
+void luaT_init (lua_State *L) {
+ static const char *const luaT_eventname[] = { /* ORDER TM */
+ "__index", "__newindex",
+ "__gc", "__mode", "__eq",
+ "__add", "__sub", "__mul", "__div",
+ "__pow", "__unm", "__lt", "__le",
+ "__concat", "__call"
+ };
+ int i;
+ for (i=0; i<TM_N; i++) {
+ G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
+ luaS_fix(G(L)->tmname[i]); /* never collect these names */
+ }
+}
+
+
+/*
+** function to be used with macro "fasttm": optimized for absence of
+** tag methods
+*/
+const TObject *luaT_gettm (Table *events, TMS event, TString *ename) {
+ const TObject *tm = luaH_getstr(events, ename);
+ lua_assert(event <= TM_EQ);
+ if (ttisnil(tm)) { /* no tag method? */
+ events->flags |= cast(lu_byte, 1u<<event); /* cache this fact */
+ return NULL;
+ }
+ else return tm;
+}
+
+
+const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event) {
+ TString *ename = G(L)->tmname[event];
+ switch (ttype(o)) {
+ case LUA_TTABLE:
+ return luaH_getstr(hvalue(o)->metatable, ename);
+ case LUA_TUSERDATA:
+ return luaH_getstr(uvalue(o)->uv.metatable, ename);
+ default:
+ return &luaO_nilobject;
+ }
+}
+
diff --git a/lib/lua/src/luacomp.c b/lib/lua/src/luacomp.c index a2d5036..bac561b 100644 --- a/lib/lua/src/luacomp.c +++ b/lib/lua/src/luacomp.c @@ -1,82 +1,82 @@ -/* - ** $Id: luacomp.c,v 1.4 2004-04-27 11:23:30 pixel Exp $ - ** Lua compiler (saves bytecodes to files; also list bytecodes) - ** Highly hacked by Nicolas "Pixel" Noble to be transformed into a - ** small form-factor LUA compiler. - ** See Copyright Notice in lua.h - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "lua.h" -#include "lauxlib.h" - -#include "lfunc.h" -#include "lmem.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstring.h" -#include "lundump.h" - -#ifndef PROGNAME -#define PROGNAME "luacomp" /* program name */ -#endif - -const char * progname = PROGNAME; /* actual program name */ - -static Proto * toproto(lua_State * L, int i) { - const Closure * c = (const Closure *) lua_topointer(L, i); - - return c->l.p; -} - -static Proto * combine(lua_State * L, int n) { - if (n == 1) - return toproto(L, -1); - else { - int i, pc = 0; - Proto * f = luaF_newproto(L); - - f->source = luaS_newliteral(L, "=(" PROGNAME ")"); - f->maxstacksize = 1; - f->p = luaM_newvector(L, n, Proto *); - f->sizep = n; - f->sizecode = 2 * n + 1; - f->code = luaM_newvector(L, f->sizecode, Instruction); - for (i = 0; i < n; i++) { - f->p[i] = toproto(L, i - n); - f->code[pc++] = CREATE_ABx(OP_CLOSURE, 0, i); - f->code[pc++] = CREATE_ABC(OP_CALL, 0, 1, 1); - } - f->code[pc++] = CREATE_ABC(OP_RETURN, 0, 1, 0); - return f; - } -} - -static void strip(lua_State * L, Proto * f) { - int i, n = f->sizep; - luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); - luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); - - luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *); - f->lineinfo = NULL; - f->sizelineinfo = 0; - f->locvars = NULL; - f->sizelocvars = 0; - f->upvalues = NULL; - f->sizeupvalues = 0; - f->source = luaS_newliteral(L, "=(none)"); - for (i = 0; i < n; i++) - strip(L, f->p[i]); -} - -void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void *uD) { - Proto * f; - - f = combine(L, lua_gettop(L)); - if (stripping) - strip(L, f); - luaU_dump(L, f, w, uD); -} +/*
+ ** $Id: luacomp.c,v 1.5 2004-11-27 21:35:20 pixel Exp $
+ ** Lua compiler (saves bytecodes to files; also list bytecodes)
+ ** Highly hacked by Nicolas "Pixel" Noble to be transformed into a
+ ** small form-factor LUA compiler.
+ ** See Copyright Notice in lua.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstring.h"
+#include "lundump.h"
+
+#ifndef PROGNAME
+#define PROGNAME "luacomp" /* program name */
+#endif
+
+const char * progname = PROGNAME; /* actual program name */
+
+static Proto * toproto(lua_State * L, int i) {
+ const Closure * c = (const Closure *) lua_topointer(L, i);
+
+ return c->l.p;
+}
+
+static Proto * combine(lua_State * L, int n) {
+ if (n == 1)
+ return toproto(L, -1);
+ else {
+ int i, pc = 0;
+ Proto * f = luaF_newproto(L);
+
+ f->source = luaS_newliteral(L, "=(" PROGNAME ")");
+ f->maxstacksize = 1;
+ f->p = luaM_newvector(L, n, Proto *);
+ f->sizep = n;
+ f->sizecode = 2 * n + 1;
+ f->code = luaM_newvector(L, f->sizecode, Instruction);
+ for (i = 0; i < n; i++) {
+ f->p[i] = toproto(L, i - n);
+ f->code[pc++] = CREATE_ABx(OP_CLOSURE, 0, i);
+ f->code[pc++] = CREATE_ABC(OP_CALL, 0, 1, 1);
+ }
+ f->code[pc++] = CREATE_ABC(OP_RETURN, 0, 1, 0);
+ return f;
+ }
+}
+
+static void strip(lua_State * L, Proto * f) {
+ int i, n = f->sizep;
+ luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
+ luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
+
+ luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
+ f->lineinfo = NULL;
+ f->sizelineinfo = 0;
+ f->locvars = NULL;
+ f->sizelocvars = 0;
+ f->upvalues = NULL;
+ f->sizeupvalues = 0;
+ f->source = luaS_newliteral(L, "=(none)");
+ for (i = 0; i < n; i++)
+ strip(L, f->p[i]);
+}
+
+void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void *uD) {
+ Proto * f;
+
+ f = combine(L, lua_gettop(L));
+ if (stripping)
+ strip(L, f);
+ luaU_dump(L, f, w, uD);
+}
diff --git a/lib/lua/src/lundump.c b/lib/lua/src/lundump.c index 3c87987..be2b586 100644 --- a/lib/lua/src/lundump.c +++ b/lib/lua/src/lundump.c @@ -1,286 +1,286 @@ -/* -** $Id: lundump.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** load pre-compiled Lua chunks -** See Copyright Notice in lua.h -*/ - -#define lundump_c - -#include "lua.h" - -#include "ldebug.h" -#include "lfunc.h" -#include "lmem.h" -#include "lopcodes.h" -#include "lstring.h" -#include "lundump.h" -#include "lzio.h" - -#define LoadByte (lu_byte) ezgetc - -typedef struct { - lua_State* L; - ZIO* Z; - Mbuffer* b; - int swap; - const char* name; -} LoadState; - -static void unexpectedEOZ (LoadState* S) -{ - luaG_runerror(S->L,"unexpected end of file in %s",S->name); -} - -static int ezgetc (LoadState* S) -{ - int c=zgetc(S->Z); - if (c==EOZ) unexpectedEOZ(S); - return c; -} - -static void ezread (LoadState* S, void* b, int n) -{ - int r=luaZ_read(S->Z,b,n); - if (r!=0) unexpectedEOZ(S); -} - -static void LoadBlock (LoadState* S, void* b, size_t size) -{ - if (S->swap) - { - char* p=(char*) b+size-1; - int n=size; - while (n--) *p--=(char)ezgetc(S); - } - else - ezread(S,b,size); -} - -static void LoadVector (LoadState* S, void* b, int m, size_t size) -{ - if (S->swap) - { - char* q=(char*) b; - while (m--) - { - char* p=q+size-1; - int n=size; - while (n--) *p--=(char)ezgetc(S); - q+=size; - } - } - else - ezread(S,b,m*size); -} - -static int LoadInt (LoadState* S) -{ - int x; - LoadBlock(S,&x,sizeof(x)); - if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name); - return x; -} - -static size_t LoadSize (LoadState* S) -{ - size_t x; - LoadBlock(S,&x,sizeof(x)); - return x; -} - -static lua_Number LoadNumber (LoadState* S) -{ - lua_Number x; - LoadBlock(S,&x,sizeof(x)); - return x; -} - -static TString* LoadString (LoadState* S) -{ - size_t size=LoadSize(S); - if (size==0) - return NULL; - else - { - char* s=luaZ_openspace(S->L,S->b,size); - ezread(S,s,size); - return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ - } -} - -static void LoadCode (LoadState* S, Proto* f) -{ - int size=LoadInt(S); - f->code=luaM_newvector(S->L,size,Instruction); - f->sizecode=size; - LoadVector(S,f->code,size,sizeof(*f->code)); -} - -static void LoadLocals (LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->locvars=luaM_newvector(S->L,n,LocVar); - f->sizelocvars=n; - for (i=0; i<n; i++) - { - f->locvars[i].varname=LoadString(S); - f->locvars[i].startpc=LoadInt(S); - f->locvars[i].endpc=LoadInt(S); - } -} - -static void LoadLines (LoadState* S, Proto* f) -{ - int size=LoadInt(S); - f->lineinfo=luaM_newvector(S->L,size,int); - f->sizelineinfo=size; - LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo)); -} - -static void LoadUpvalues (LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - if (n!=0 && n!=f->nups) - luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d", - S->name,n,f->nups); - f->upvalues=luaM_newvector(S->L,n,TString*); - f->sizeupvalues=n; - for (i=0; i<n; i++) f->upvalues[i]=LoadString(S); -} - -static Proto* LoadFunction (LoadState* S, TString* p); - -static void LoadConstants (LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->k=luaM_newvector(S->L,n,TObject); - f->sizek=n; - for (i=0; i<n; i++) - { - TObject* o=&f->k[i]; - int t=LoadByte(S); - switch (t) - { - case LUA_TNUMBER: - setnvalue(o,LoadNumber(S)); - break; - case LUA_TSTRING: - setsvalue2n(o,LoadString(S)); - break; - case LUA_TNIL: - setnilvalue(o); - break; - default: - luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name); - break; - } - } - n=LoadInt(S); - f->p=luaM_newvector(S->L,n,Proto*); - f->sizep=n; - for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source); -} - -static Proto* LoadFunction (LoadState* S, TString* p) -{ - Proto* f=luaF_newproto(S->L); - f->source=LoadString(S); if (f->source==NULL) f->source=p; - f->lineDefined=LoadInt(S); - f->nups=LoadByte(S); - f->numparams=LoadByte(S); - f->is_vararg=LoadByte(S); - f->maxstacksize=LoadByte(S); - LoadLines(S,f); - LoadLocals(S,f); - LoadUpvalues(S,f); - LoadConstants(S,f); - LoadCode(S,f); -#ifndef TRUST_BINARIES - if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name); -#endif - return f; -} - -static void LoadSignature (LoadState* S) -{ - const char* s=LUA_SIGNATURE; - while (*s!=0 && ezgetc(S)==*s) - ++s; - if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name); -} - -static void TestSize (LoadState* S, int s, const char* what) -{ - int r=LoadByte(S); - if (r!=s) - luaG_runerror(S->L,"virtual machine mismatch in %s: " - "size of %s is %d but read %d",S->name,what,s,r); -} - -#define TESTSIZE(s,w) TestSize(S,s,w) -#define V(v) v/16,v%16 - -static void LoadHeader (LoadState* S) -{ - int version; - lua_Number x,tx=TEST_NUMBER; - LoadSignature(S); - version=LoadByte(S); - if (version>VERSION) - luaG_runerror(S->L,"%s too new: " - "read version %d.%d; expected at most %d.%d", - S->name,V(version),V(VERSION)); - if (version<VERSION0) /* check last major change */ - luaG_runerror(S->L,"%s too old: " - "read version %d.%d; expected at least %d.%d", - S->name,V(version),V(VERSION0)); - S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */ - TESTSIZE(sizeof(int),"int"); - TESTSIZE(sizeof(size_t), "size_t"); - TESTSIZE(sizeof(Instruction), "Instruction"); - TESTSIZE(SIZE_OP, "OP"); - TESTSIZE(SIZE_A, "A"); - TESTSIZE(SIZE_B, "B"); - TESTSIZE(SIZE_C, "C"); - TESTSIZE(sizeof(lua_Number), "number"); - x=LoadNumber(S); - if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */ - luaG_runerror(S->L,"unknown number format in %s",S->name); -} - -static Proto* LoadChunk (LoadState* S) -{ - LoadHeader(S); - return LoadFunction(S,NULL); -} - -/* -** load precompiled chunk -*/ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff) -{ - LoadState S; - const char* s=zname(Z); - if (*s=='@' || *s=='=') - S.name=s+1; - else if (*s==LUA_SIGNATURE[0]) - S.name="binary string"; - else - S.name=s; - S.L=L; - S.Z=Z; - S.b=buff; - return LoadChunk(&S); -} - -/* -** find byte order -*/ -int luaU_endianness (void) -{ - int x=1; - return *(char*)&x; -} +/*
+** $Id: lundump.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** load pre-compiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#define lundump_c
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lstring.h"
+#include "lundump.h"
+#include "lzio.h"
+
+#define LoadByte (lu_byte) ezgetc
+
+typedef struct {
+ lua_State* L;
+ ZIO* Z;
+ Mbuffer* b;
+ int swap;
+ const char* name;
+} LoadState;
+
+static void unexpectedEOZ (LoadState* S)
+{
+ luaG_runerror(S->L,"unexpected end of file in %s",S->name);
+}
+
+static int ezgetc (LoadState* S)
+{
+ int c=zgetc(S->Z);
+ if (c==EOZ) unexpectedEOZ(S);
+ return c;
+}
+
+static void ezread (LoadState* S, void* b, int n)
+{
+ int r=luaZ_read(S->Z,b,n);
+ if (r!=0) unexpectedEOZ(S);
+}
+
+static void LoadBlock (LoadState* S, void* b, size_t size)
+{
+ if (S->swap)
+ {
+ char* p=(char*) b+size-1;
+ int n=size;
+ while (n--) *p--=(char)ezgetc(S);
+ }
+ else
+ ezread(S,b,size);
+}
+
+static void LoadVector (LoadState* S, void* b, int m, size_t size)
+{
+ if (S->swap)
+ {
+ char* q=(char*) b;
+ while (m--)
+ {
+ char* p=q+size-1;
+ int n=size;
+ while (n--) *p--=(char)ezgetc(S);
+ q+=size;
+ }
+ }
+ else
+ ezread(S,b,m*size);
+}
+
+static int LoadInt (LoadState* S)
+{
+ int x;
+ LoadBlock(S,&x,sizeof(x));
+ if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name);
+ return x;
+}
+
+static size_t LoadSize (LoadState* S)
+{
+ size_t x;
+ LoadBlock(S,&x,sizeof(x));
+ return x;
+}
+
+static lua_Number LoadNumber (LoadState* S)
+{
+ lua_Number x;
+ LoadBlock(S,&x,sizeof(x));
+ return x;
+}
+
+static TString* LoadString (LoadState* S)
+{
+ size_t size=LoadSize(S);
+ if (size==0)
+ return NULL;
+ else
+ {
+ char* s=luaZ_openspace(S->L,S->b,size);
+ ezread(S,s,size);
+ return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */
+ }
+}
+
+static void LoadCode (LoadState* S, Proto* f)
+{
+ int size=LoadInt(S);
+ f->code=luaM_newvector(S->L,size,Instruction);
+ f->sizecode=size;
+ LoadVector(S,f->code,size,sizeof(*f->code));
+}
+
+static void LoadLocals (LoadState* S, Proto* f)
+{
+ int i,n;
+ n=LoadInt(S);
+ f->locvars=luaM_newvector(S->L,n,LocVar);
+ f->sizelocvars=n;
+ for (i=0; i<n; i++)
+ {
+ f->locvars[i].varname=LoadString(S);
+ f->locvars[i].startpc=LoadInt(S);
+ f->locvars[i].endpc=LoadInt(S);
+ }
+}
+
+static void LoadLines (LoadState* S, Proto* f)
+{
+ int size=LoadInt(S);
+ f->lineinfo=luaM_newvector(S->L,size,int);
+ f->sizelineinfo=size;
+ LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo));
+}
+
+static void LoadUpvalues (LoadState* S, Proto* f)
+{
+ int i,n;
+ n=LoadInt(S);
+ if (n!=0 && n!=f->nups)
+ luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d",
+ S->name,n,f->nups);
+ f->upvalues=luaM_newvector(S->L,n,TString*);
+ f->sizeupvalues=n;
+ for (i=0; i<n; i++) f->upvalues[i]=LoadString(S);
+}
+
+static Proto* LoadFunction (LoadState* S, TString* p);
+
+static void LoadConstants (LoadState* S, Proto* f)
+{
+ int i,n;
+ n=LoadInt(S);
+ f->k=luaM_newvector(S->L,n,TObject);
+ f->sizek=n;
+ for (i=0; i<n; i++)
+ {
+ TObject* o=&f->k[i];
+ int t=LoadByte(S);
+ switch (t)
+ {
+ case LUA_TNUMBER:
+ setnvalue(o,LoadNumber(S));
+ break;
+ case LUA_TSTRING:
+ setsvalue2n(o,LoadString(S));
+ break;
+ case LUA_TNIL:
+ setnilvalue(o);
+ break;
+ default:
+ luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name);
+ break;
+ }
+ }
+ n=LoadInt(S);
+ f->p=luaM_newvector(S->L,n,Proto*);
+ f->sizep=n;
+ for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source);
+}
+
+static Proto* LoadFunction (LoadState* S, TString* p)
+{
+ Proto* f=luaF_newproto(S->L);
+ f->source=LoadString(S); if (f->source==NULL) f->source=p;
+ f->lineDefined=LoadInt(S);
+ f->nups=LoadByte(S);
+ f->numparams=LoadByte(S);
+ f->is_vararg=LoadByte(S);
+ f->maxstacksize=LoadByte(S);
+ LoadLines(S,f);
+ LoadLocals(S,f);
+ LoadUpvalues(S,f);
+ LoadConstants(S,f);
+ LoadCode(S,f);
+#ifndef TRUST_BINARIES
+ if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name);
+#endif
+ return f;
+}
+
+static void LoadSignature (LoadState* S)
+{
+ const char* s=LUA_SIGNATURE;
+ while (*s!=0 && ezgetc(S)==*s)
+ ++s;
+ if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name);
+}
+
+static void TestSize (LoadState* S, int s, const char* what)
+{
+ int r=LoadByte(S);
+ if (r!=s)
+ luaG_runerror(S->L,"virtual machine mismatch in %s: "
+ "size of %s is %d but read %d",S->name,what,s,r);
+}
+
+#define TESTSIZE(s,w) TestSize(S,s,w)
+#define V(v) v/16,v%16
+
+static void LoadHeader (LoadState* S)
+{
+ int version;
+ lua_Number x,tx=TEST_NUMBER;
+ LoadSignature(S);
+ version=LoadByte(S);
+ if (version>VERSION)
+ luaG_runerror(S->L,"%s too new: "
+ "read version %d.%d; expected at most %d.%d",
+ S->name,V(version),V(VERSION));
+ if (version<VERSION0) /* check last major change */
+ luaG_runerror(S->L,"%s too old: "
+ "read version %d.%d; expected at least %d.%d",
+ S->name,V(version),V(VERSION0));
+ S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */
+ TESTSIZE(sizeof(int),"int");
+ TESTSIZE(sizeof(size_t), "size_t");
+ TESTSIZE(sizeof(Instruction), "Instruction");
+ TESTSIZE(SIZE_OP, "OP");
+ TESTSIZE(SIZE_A, "A");
+ TESTSIZE(SIZE_B, "B");
+ TESTSIZE(SIZE_C, "C");
+ TESTSIZE(sizeof(lua_Number), "number");
+ x=LoadNumber(S);
+ if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */
+ luaG_runerror(S->L,"unknown number format in %s",S->name);
+}
+
+static Proto* LoadChunk (LoadState* S)
+{
+ LoadHeader(S);
+ return LoadFunction(S,NULL);
+}
+
+/*
+** load precompiled chunk
+*/
+Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff)
+{
+ LoadState S;
+ const char* s=zname(Z);
+ if (*s=='@' || *s=='=')
+ S.name=s+1;
+ else if (*s==LUA_SIGNATURE[0])
+ S.name="binary string";
+ else
+ S.name=s;
+ S.L=L;
+ S.Z=Z;
+ S.b=buff;
+ return LoadChunk(&S);
+}
+
+/*
+** find byte order
+*/
+int luaU_endianness (void)
+{
+ int x=1;
+ return *(char*)&x;
+}
diff --git a/lib/lua/src/lvm.c b/lib/lua/src/lvm.c index 3a8a974..c22c258 100644 --- a/lib/lua/src/lvm.c +++ b/lib/lua/src/lvm.c @@ -1,784 +1,784 @@ -/* -** $Id: lvm.c,v 1.3 2004-07-23 13:08:23 pixel Exp $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - - -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> - -/* needed only when `lua_number2str' uses `sprintf' */ -#include <stdio.h> - -#define lvm_c - -#include "lua.h" - -#include "ldebug.h" -#include "ldo.h" -#include "lfunc.h" -#include "lgc.h" -#include "lobject.h" -#include "lopcodes.h" -#include "lstate.h" -#include "lstring.h" -#include "ltable.h" -#include "ltm.h" -#include "lvm.h" - - - -/* function to convert a lua_Number to a string */ -#ifndef lua_number2str -#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) -#endif - - -/* limit for table tag-method chains (to avoid loops) */ -#define MAXTAGLOOP 100 - - -const TObject *luaV_tonumber (const TObject *obj, TObject *n) { - lua_Number num; - if (ttisnumber(obj)) return obj; - if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { - setnvalue(n, num); - return n; - } - else - return NULL; -} - - -int luaV_tostring (lua_State *L, StkId obj) { - if (!ttisnumber(obj)) - return 0; - else { - char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ - lua_number2str(s, nvalue(obj)); - setsvalue2s(obj, luaS_new(L, s)); - return 1; - } -} - - -static void traceexec (lua_State *L) { - lu_byte mask = L->hookmask; - if (mask > LUA_MASKLINE) { /* instruction-hook set? */ - if (L->hookcount == 0) { - resethookcount(L); - luaD_callhook(L, LUA_HOOKCOUNT, -1); - return; - } - } - if (mask & LUA_MASKLINE) { - CallInfo *ci = L->ci; - Proto *p = ci_func(ci)->l.p; - int newline = getline(p, pcRel(*ci->u.l.pc, p)); - if (!L->hookinit) { - luaG_inithooks(L); - return; - } - lua_assert(ci->state & CI_HASFRAME); - if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */ - ci->u.l.savedpc = *ci->u.l.pc; /* initialize `savedpc' */ - /* calls linehook when enters a new line or jumps back (loop) */ - if (*ci->u.l.pc <= ci->u.l.savedpc || - newline != getline(p, pcRel(ci->u.l.savedpc, p))) { - luaD_callhook(L, LUA_HOOKLINE, newline); - ci = L->ci; /* previous call may reallocate `ci' */ - } - ci->u.l.savedpc = *ci->u.l.pc; - } -} - - -static void callTMres (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - luaD_checkstack(L, 3); /* cannot check before (could invalidate p1, p2) */ - L->top += 3; - luaD_call(L, L->top - 3, 1); - L->top--; /* result will be in L->top */ -} - - - -static void callTM (lua_State *L, const TObject *f, - const TObject *p1, const TObject *p2, const TObject *p3) { - setobj2s(L->top, f); /* push function */ - setobj2s(L->top+1, p1); /* 1st argument */ - setobj2s(L->top+2, p2); /* 2nd argument */ - setobj2s(L->top+3, p3); /* 3th argument */ - luaD_checkstack(L, 4); /* cannot check before (could invalidate p1...p3) */ - L->top += 4; - luaD_call(L, L->top - 4, 0); -} - - -static const TObject *luaV_index (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); - if (tm == NULL) return &luaO_nilobject; /* no TM */ - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - -static const TObject *luaV_getnotable (lua_State *L, const TObject *t, - TObject *key, int loop) { - const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (ttisnil(tm)) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTMres(L, tm, t, key); - return L->top; - } - else return luaV_gettable(L, tm, key, loop); -} - - -/* -** Function to index a table. -** Receives the table at `t' and the key at `key'. -** leaves the result at `res'. -*/ -const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, - int loop) { - if (loop > MAXTAGLOOP) - luaG_runerror(L, "loop in gettable"); - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - const TObject *v = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(v)) return v; - else return luaV_index(L, t, key, loop+1); - } - else return luaV_getnotable(L, t, key, loop+1); -} - - -/* -** Receives table at `t', key at `key' and value at `val'. -*/ -void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { - const TObject *tm; - int loop = 0; - do { - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ - if (!ttisnil(oldval) || /* result is no nil? */ - (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ - setobj2t(oldval, val); /* write barrier */ - return; - } - /* else will try the tag method */ - } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTM(L, tm, t, key, val); - return; - } - t = tm; /* else repeat with `tm' */ - } while (++loop <= MAXTAGLOOP); - luaG_runerror(L, "loop in settable"); -} - - -static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, - StkId res, TMS event) { - ptrdiff_t result = savestack(L, res); - const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ - if (ttisnil(tm)) - tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (!ttisfunction(tm)) return 0; - callTMres(L, tm, p1, p2); - res = restorestack(L, result); /* previous call may change stack */ - setobjs2s(res, L->top); - return 1; -} - - -static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2, - TMS event) { - const TObject *tm1 = fasttm(L, mt1, event); - const TObject *tm2; - if (tm1 == NULL) return NULL; /* no metamethod */ - if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ - tm2 = fasttm(L, mt2, event); - if (tm2 == NULL) return NULL; /* no metamethod */ - if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ - return tm1; - return NULL; -} - - -static int call_orderTM (lua_State *L, const TObject *p1, const TObject *p2, - TMS event) { - const TObject *tm1 = luaT_gettmbyobj(L, p1, event); - const TObject *tm2; - if (ttisnil(tm1)) return -1; /* no metamethod? */ - tm2 = luaT_gettmbyobj(L, p2, event); - if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ - return -1; - callTMres(L, tm1, p1, p2); - return !l_isfalse(L->top); -} - - -static int luaV_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = ls->tsv.len; - const char *r = getstr(rs); - size_t lr = rs->tsv.len; - for (;;) { - int temp = strcoll(l, r); - if (temp != 0) return temp; - else { /* strings are equal up to a `\0' */ - size_t len = strlen(l); /* index of first `\0' in both strings */ - if (len == lr) /* r is finished? */ - return (len == ll) ? 0 : 1; - else if (len == ll) /* l is finished? */ - return -1; /* l is smaller than r (because r is not finished) */ - /* both strings longer than `len'; go on comparing (after the `\0') */ - len++; - l += len; ll -= len; r += len; lr -= len; - } - } -} - - -int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { - int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) - return nvalue(l) < nvalue(r); - else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0; - else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) - return res; - return luaG_ordererror(L, l, r); -} - - -static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { - int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) - return nvalue(l) <= nvalue(r); - else if (ttisstring(l)) - return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0; - else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ - return res; - else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ - return !res; - return luaG_ordererror(L, l, r); -} - - -int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { - const TObject *tm; - lua_assert(ttype(t1) == ttype(t2)); - switch (ttype(t1)) { - case LUA_TNIL: return 1; - case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); - case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ - case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); - case LUA_TUSERDATA: { - if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->uv.metatable, uvalue(t2)->uv.metatable, - TM_EQ); - break; /* will try TM */ - } - case LUA_TTABLE: { - if (hvalue(t1) == hvalue(t2)) return 1; - tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); - break; /* will try TM */ - } - default: return gcvalue(t1) == gcvalue(t2); - } - if (tm == NULL) return 0; /* no TM? */ - callTMres(L, tm, t1, t2); /* call TM */ - return !l_isfalse(L->top); -} - - -void luaV_concat (lua_State *L, int total, int last) { - do { - StkId top = L->base + last + 1; - int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!tostring(L, top-2) || !tostring(L, top-1)) { - if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) - luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ - /* at least two string values; get as many as possible */ - lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + - cast(lu_mem, tsvalue(top-2)->tsv.len); - char *buffer; - int i; - while (n < total && tostring(L, top-n-1)) { /* collect total length */ - tl += tsvalue(top-n-1)->tsv.len; - n++; - } - if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); - buffer = luaZ_openspace(L, &G(L)->buff, tl); - tl = 0; - for (i=n; i>0; i--) { /* concat all strings */ - size_t l = tsvalue(top-i)->tsv.len; - memcpy(buffer+tl, svalue(top-i), l); - tl += l; - } - setsvalue2s(top-n, luaS_newlstr(L, buffer, tl)); - } - total -= n-1; /* got `n' strings to create 1 new */ - last -= n-1; - } while (total > 1); /* repeat until only 1 result left */ -} - - -static void Arith (lua_State *L, StkId ra, - const TObject *rb, const TObject *rc, TMS op) { - TObject tempb, tempc; - const TObject *b, *c; - if ((b = luaV_tonumber(rb, &tempb)) != NULL && - (c = luaV_tonumber(rc, &tempc)) != NULL) { - switch (op) { - case TM_ADD: setnvalue(ra, nvalue(b) + nvalue(c)); break; - case TM_SUB: setnvalue(ra, nvalue(b) - nvalue(c)); break; - case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; - case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; - case TM_POW: { - const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); - ptrdiff_t res = savestack(L, ra); - if (!ttisfunction(f)) - luaG_runerror(L, "`__pow' (`^' operator) is not a function"); - callTMres(L, f, b, c); - ra = restorestack(L, res); /* previous call may change stack */ - setobjs2s(ra, L->top); - break; - } - default: lua_assert(0); break; - } - } - else if (!call_binTM(L, rb, rc, ra, op)) - luaG_aritherror(L, rb, rc); -} - - - -/* -** some macros for common tasks in `luaV_execute' -*/ - -#define runtime_check(L, c) { if (!(c)) return 0; } - -#define RA(i) (base+GETARG_A(i)) -/* to be used after possible stack reallocation */ -#define XRA(i) (L->base+GETARG_A(i)) -#define RB(i) (base+GETARG_B(i)) -#define RKB(i) ((GETARG_B(i) < MAXSTACK) ? RB(i) : k+GETARG_B(i)-MAXSTACK) -#define RC(i) (base+GETARG_C(i)) -#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? RC(i) : k+GETARG_C(i)-MAXSTACK) -#define KBx(i) (k+GETARG_Bx(i)) - - -#define dojump(pc, i) ((pc) += (i)) - - -StkId luaV_execute (lua_State *L) { - LClosure *cl; - TObject *k; - const Instruction *pc; - callentry: /* entry point when calling new functions */ - L->ci->u.l.pc = &pc; - if (L->hookmask & LUA_MASKCALL) - luaD_callhook(L, LUA_HOOKCALL, -1); - retentry: /* entry point when returning to old functions */ - lua_assert(L->ci->state == CI_SAVEDPC || - L->ci->state == (CI_SAVEDPC | CI_CALLING)); - L->ci->state = CI_HASFRAME; /* activate frame */ - pc = L->ci->u.l.savedpc; - cl = &clvalue(L->base - 1)->l; - k = cl->p->k; - /* main loop of interpreter */ - for (;;) { - const Instruction i = *pc++; - StkId base, ra; - if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && - (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L); - if (L->ci->state & CI_YIELD) { /* did hook yield? */ - L->ci->u.l.savedpc = pc - 1; - L->ci->state = CI_YIELD | CI_SAVEDPC; - return NULL; - } - if (L->ci->state & CI_BREAK) { /* did hook break? */ - luaG_runerror(L, "breaking"); - L->ci->state &= ~CI_BREAK; - } - } - /* warning!! several calls may realloc the stack and invalidate `ra' */ - base = L->base; - ra = RA(i); - lua_assert(L->ci->state & CI_HASFRAME); - lua_assert(base == L->ci->base); - lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); - lua_assert(L->top == L->ci->top || - GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || - GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); - switch (GET_OPCODE(i)) { - case OP_MOVE: { - setobjs2s(ra, RB(i)); - break; - } - case OP_LOADK: { - setobj2s(ra, KBx(i)); - break; - } - case OP_LOADBOOL: { - setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ - break; - } - case OP_LOADNIL: { - TObject *rb = RB(i); - do { - setnilvalue(rb--); - } while (rb >= ra); - break; - } - case OP_GETUPVAL: { - int b = GETARG_B(i); - setobj2s(ra, cl->upvals[b]->v); - break; - } - case OP_GETGLOBAL: { - TObject *rb = KBx(i); - const TObject *v; - lua_assert(ttisstring(rb) && ttistable(&cl->g)); - v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); - break; - } - case OP_GETTABLE: { - StkId rb = RB(i); - TObject *rc = RKC(i); - if (ttistable(rb)) { - const TObject *v = luaH_get(hvalue(rb), rc); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); - break; - } - case OP_SETGLOBAL: { - lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - luaV_settable(L, &cl->g, KBx(i), ra); - break; - } - case OP_SETUPVAL: { - int b = GETARG_B(i); - setobj(cl->upvals[b]->v, ra); /* write barrier */ - break; - } - case OP_SETTABLE: { - luaV_settable(L, ra, RKB(i), RKC(i)); - break; - } - case OP_NEWTABLE: { - int b = GETARG_B(i); - b = fb2int(b); - sethvalue(ra, luaH_new(L, b, GETARG_C(i))); - luaC_checkGC(L); - break; - } - case OP_SELF: { - StkId rb = RB(i); - TObject *rc = RKC(i); - runtime_check(L, ttisstring(rc)); - setobjs2s(ra+1, rb); - if (ttistable(rb)) { - const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); - if (!ttisnil(v)) { setobj2s(ra, v); } - else - setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); - } - else - setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); - break; - } - case OP_ADD: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) + nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_ADD); - break; - } - case OP_SUB: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) - nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_SUB); - break; - } - case OP_MUL: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) * nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_MUL); - break; - } - case OP_DIV: { - TObject *rb = RKB(i); - TObject *rc = RKC(i); - if (ttisnumber(rb) && ttisnumber(rc)) { - setnvalue(ra, nvalue(rb) / nvalue(rc)); - } - else - Arith(L, ra, rb, rc, TM_DIV); - break; - } - case OP_POW: { - Arith(L, ra, RKB(i), RKC(i), TM_POW); - break; - } - case OP_UNM: { - const TObject *rb = RB(i); - TObject temp; - if (tonumber(rb, &temp)) { - setnvalue(ra, -nvalue(rb)); - } - else { - setnilvalue(&temp); - if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) - luaG_aritherror(L, RB(i), &temp); - } - break; - } - case OP_NOT: { - int res = l_isfalse(RB(i)); /* next assignment may change this value */ - setbvalue(ra, res); - break; - } - case OP_CONCAT: { - int b = GETARG_B(i); - int c = GETARG_C(i); - luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ - base = L->base; - setobjs2s(RA(i), base+b); - luaC_checkGC(L); - break; - } - case OP_JMP: { - dojump(pc, GETARG_sBx(i)); - break; - } - case OP_EQ: { - if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; - } - case OP_LT: { - if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; - } - case OP_LE: { - if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; - else dojump(pc, GETARG_sBx(*pc) + 1); - break; - } - case OP_TEST: { - TObject *rb = RB(i); - if (l_isfalse(rb) == GETARG_C(i)) pc++; - else { - setobjs2s(ra, rb); - dojump(pc, GETARG_sBx(*pc) + 1); - } - break; - } - case OP_CALL: - case OP_TAILCALL: { - StkId firstResult; - int b = GETARG_B(i); - int nresults; - if (b != 0) L->top = ra+b; /* else previous instruction set top */ - nresults = GETARG_C(i) - 1; - firstResult = luaD_precall(L, ra); - if (firstResult) { - if (firstResult > L->top) { /* yield? */ - lua_assert(L->ci->state == (CI_C | CI_YIELD)); - (L->ci - 1)->u.l.savedpc = pc; - (L->ci - 1)->state = CI_SAVEDPC; - return NULL; - } - /* it was a C function (`precall' called it); adjust results */ - luaD_poscall(L, nresults, firstResult); - if (nresults >= 0) L->top = L->ci->top; - } - else { /* it is a Lua function */ - if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ - (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ - (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); - } - else { /* tail call: put new frame in place of previous one */ - int aux; - base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ - ra = RA(i); - if (L->openupval) luaF_close(L, base); - for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ - setobjs2s(base+aux-1, ra+aux); - (L->ci - 1)->top = L->top = base+aux; /* correct top */ - lua_assert(L->ci->state & CI_SAVEDPC); - (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; - (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ - (L->ci - 1)->state = CI_SAVEDPC; - L->ci--; /* remove new frame */ - L->base = L->ci->base; - } - goto callentry; - } - break; - } - case OP_RETURN: { - CallInfo *ci = L->ci - 1; /* previous function frame */ - int b = GETARG_B(i); - if (b != 0) L->top = ra+b-1; - lua_assert(L->ci->state & CI_HASFRAME); - if (L->openupval) luaF_close(L, base); - L->ci->state = CI_SAVEDPC; /* deactivate current function */ - L->ci->u.l.savedpc = pc; - /* previous function was running `here'? */ - if (!(ci->state & CI_CALLING)) { - lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); - return ra; /* no: return */ - } - else { /* yes: continue its execution */ - int nresults; - lua_assert(ci->u.l.pc == &pc && - ttisfunction(ci->base - 1) && - (ci->state & CI_SAVEDPC)); - lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); - nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; - luaD_poscall(L, nresults, ra); - if (nresults >= 0) L->top = L->ci->top; - goto retentry; - } - } - case OP_FORLOOP: { - lua_Number step, idx, limit; - const TObject *plimit = ra+1; - const TObject *pstep = ra+2; - if (!ttisnumber(ra)) - luaG_runerror(L, "`for' initial value must be a number"); - if (!tonumber(plimit, ra+1)) - luaG_runerror(L, "`for' limit must be a number"); - if (!tonumber(pstep, ra+2)) - luaG_runerror(L, "`for' step must be a number"); - step = nvalue(pstep); - idx = nvalue(ra) + step; /* increment index */ - limit = nvalue(plimit); - if (step > 0 ? idx <= limit : idx >= limit) { - dojump(pc, GETARG_sBx(i)); /* jump back */ - chgnvalue(ra, idx); /* update index */ - } - break; - } - case OP_TFORLOOP: { - int nvar = GETARG_C(i) + 1; - StkId cb = ra + nvar + 2; /* call base */ - setobjs2s(cb, ra); - setobjs2s(cb+1, ra+1); - setobjs2s(cb+2, ra+2); - L->top = cb+3; /* func. + 2 args (state and index) */ - luaD_call(L, cb, nvar); - L->top = L->ci->top; - ra = XRA(i) + 2; /* final position of first result */ - cb = ra + nvar; - do { /* move results to proper positions */ - nvar--; - setobjs2s(ra+nvar, cb+nvar); - } while (nvar > 0); - if (ttisnil(ra)) /* break loop? */ - pc++; /* skip jump (break loop) */ - else - dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ - break; - } - case OP_TFORPREP: { /* for compatibility only */ - if (ttistable(ra)) { - setobjs2s(ra+1, ra); - setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); - } - dojump(pc, GETARG_sBx(i)); - break; - } - case OP_SETLIST: - case OP_SETLISTO: { - int bc; - int n; - Table *h; - runtime_check(L, ttistable(ra)); - h = hvalue(ra); - bc = GETARG_Bx(i); - if (GET_OPCODE(i) == OP_SETLIST) - n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; - else { - n = L->top - ra - 1; - L->top = L->ci->top; - } - bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ - for (; n > 0; n--) - setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ - break; - } - case OP_CLOSE: { - luaF_close(L, ra); - break; - } - case OP_CLOSURE: { - Proto *p; - Closure *ncl; - int nup, j; - p = cl->p->p[GETARG_Bx(i)]; - nup = p->nups; - ncl = luaF_newLclosure(L, nup, &cl->g); - ncl->l.p = p; - for (j=0; j<nup; j++, pc++) { - if (GET_OPCODE(*pc) == OP_GETUPVAL) - ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; - else { - lua_assert(GET_OPCODE(*pc) == OP_MOVE); - ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); - } - } - setclvalue(ra, ncl); - luaC_checkGC(L); - break; - } - } - } -} - +/*
+** $Id: lvm.c,v 1.4 2004-11-27 21:35:20 pixel Exp $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* needed only when `lua_number2str' uses `sprintf' */
+#include <stdio.h>
+
+#define lvm_c
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+
+/* function to convert a lua_Number to a string */
+#ifndef lua_number2str
+#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
+#endif
+
+
+/* limit for table tag-method chains (to avoid loops) */
+#define MAXTAGLOOP 100
+
+
+const TObject *luaV_tonumber (const TObject *obj, TObject *n) {
+ lua_Number num;
+ if (ttisnumber(obj)) return obj;
+ if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
+ setnvalue(n, num);
+ return n;
+ }
+ else
+ return NULL;
+}
+
+
+int luaV_tostring (lua_State *L, StkId obj) {
+ if (!ttisnumber(obj))
+ return 0;
+ else {
+ char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */
+ lua_number2str(s, nvalue(obj));
+ setsvalue2s(obj, luaS_new(L, s));
+ return 1;
+ }
+}
+
+
+static void traceexec (lua_State *L) {
+ lu_byte mask = L->hookmask;
+ if (mask > LUA_MASKLINE) { /* instruction-hook set? */
+ if (L->hookcount == 0) {
+ resethookcount(L);
+ luaD_callhook(L, LUA_HOOKCOUNT, -1);
+ return;
+ }
+ }
+ if (mask & LUA_MASKLINE) {
+ CallInfo *ci = L->ci;
+ Proto *p = ci_func(ci)->l.p;
+ int newline = getline(p, pcRel(*ci->u.l.pc, p));
+ if (!L->hookinit) {
+ luaG_inithooks(L);
+ return;
+ }
+ lua_assert(ci->state & CI_HASFRAME);
+ if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */
+ ci->u.l.savedpc = *ci->u.l.pc; /* initialize `savedpc' */
+ /* calls linehook when enters a new line or jumps back (loop) */
+ if (*ci->u.l.pc <= ci->u.l.savedpc ||
+ newline != getline(p, pcRel(ci->u.l.savedpc, p))) {
+ luaD_callhook(L, LUA_HOOKLINE, newline);
+ ci = L->ci; /* previous call may reallocate `ci' */
+ }
+ ci->u.l.savedpc = *ci->u.l.pc;
+ }
+}
+
+
+static void callTMres (lua_State *L, const TObject *f,
+ const TObject *p1, const TObject *p2) {
+ setobj2s(L->top, f); /* push function */
+ setobj2s(L->top+1, p1); /* 1st argument */
+ setobj2s(L->top+2, p2); /* 2nd argument */
+ luaD_checkstack(L, 3); /* cannot check before (could invalidate p1, p2) */
+ L->top += 3;
+ luaD_call(L, L->top - 3, 1);
+ L->top--; /* result will be in L->top */
+}
+
+
+
+static void callTM (lua_State *L, const TObject *f,
+ const TObject *p1, const TObject *p2, const TObject *p3) {
+ setobj2s(L->top, f); /* push function */
+ setobj2s(L->top+1, p1); /* 1st argument */
+ setobj2s(L->top+2, p2); /* 2nd argument */
+ setobj2s(L->top+3, p3); /* 3th argument */
+ luaD_checkstack(L, 4); /* cannot check before (could invalidate p1...p3) */
+ L->top += 4;
+ luaD_call(L, L->top - 4, 0);
+}
+
+
+static const TObject *luaV_index (lua_State *L, const TObject *t,
+ TObject *key, int loop) {
+ const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX);
+ if (tm == NULL) return &luaO_nilobject; /* no TM */
+ if (ttisfunction(tm)) {
+ callTMres(L, tm, t, key);
+ return L->top;
+ }
+ else return luaV_gettable(L, tm, key, loop);
+}
+
+static const TObject *luaV_getnotable (lua_State *L, const TObject *t,
+ TObject *key, int loop) {
+ const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX);
+ if (ttisnil(tm))
+ luaG_typeerror(L, t, "index");
+ if (ttisfunction(tm)) {
+ callTMres(L, tm, t, key);
+ return L->top;
+ }
+ else return luaV_gettable(L, tm, key, loop);
+}
+
+
+/*
+** Function to index a table.
+** Receives the table at `t' and the key at `key'.
+** leaves the result at `res'.
+*/
+const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key,
+ int loop) {
+ if (loop > MAXTAGLOOP)
+ luaG_runerror(L, "loop in gettable");
+ if (ttistable(t)) { /* `t' is a table? */
+ Table *h = hvalue(t);
+ const TObject *v = luaH_get(h, key); /* do a primitive get */
+ if (!ttisnil(v)) return v;
+ else return luaV_index(L, t, key, loop+1);
+ }
+ else return luaV_getnotable(L, t, key, loop+1);
+}
+
+
+/*
+** Receives table at `t', key at `key' and value at `val'.
+*/
+void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) {
+ const TObject *tm;
+ int loop = 0;
+ do {
+ if (ttistable(t)) { /* `t' is a table? */
+ Table *h = hvalue(t);
+ TObject *oldval = luaH_set(L, h, key); /* do a primitive set */
+ if (!ttisnil(oldval) || /* result is no nil? */
+ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
+ setobj2t(oldval, val); /* write barrier */
+ return;
+ }
+ /* else will try the tag method */
+ }
+ else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
+ luaG_typeerror(L, t, "index");
+ if (ttisfunction(tm)) {
+ callTM(L, tm, t, key, val);
+ return;
+ }
+ t = tm; /* else repeat with `tm' */
+ } while (++loop <= MAXTAGLOOP);
+ luaG_runerror(L, "loop in settable");
+}
+
+
+static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2,
+ StkId res, TMS event) {
+ ptrdiff_t result = savestack(L, res);
+ const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
+ if (ttisnil(tm))
+ tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
+ if (!ttisfunction(tm)) return 0;
+ callTMres(L, tm, p1, p2);
+ res = restorestack(L, result); /* previous call may change stack */
+ setobjs2s(res, L->top);
+ return 1;
+}
+
+
+static const TObject *get_compTM (lua_State *L, Table *mt1, Table *mt2,
+ TMS event) {
+ const TObject *tm1 = fasttm(L, mt1, event);
+ const TObject *tm2;
+ if (tm1 == NULL) return NULL; /* no metamethod */
+ if (mt1 == mt2) return tm1; /* same metatables => same metamethods */
+ tm2 = fasttm(L, mt2, event);
+ if (tm2 == NULL) return NULL; /* no metamethod */
+ if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */
+ return tm1;
+ return NULL;
+}
+
+
+static int call_orderTM (lua_State *L, const TObject *p1, const TObject *p2,
+ TMS event) {
+ const TObject *tm1 = luaT_gettmbyobj(L, p1, event);
+ const TObject *tm2;
+ if (ttisnil(tm1)) return -1; /* no metamethod? */
+ tm2 = luaT_gettmbyobj(L, p2, event);
+ if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */
+ return -1;
+ callTMres(L, tm1, p1, p2);
+ return !l_isfalse(L->top);
+}
+
+
+static int luaV_strcmp (const TString *ls, const TString *rs) {
+ const char *l = getstr(ls);
+ size_t ll = ls->tsv.len;
+ const char *r = getstr(rs);
+ size_t lr = rs->tsv.len;
+ for (;;) {
+ int temp = strcoll(l, r);
+ if (temp != 0) return temp;
+ else { /* strings are equal up to a `\0' */
+ size_t len = strlen(l); /* index of first `\0' in both strings */
+ if (len == lr) /* r is finished? */
+ return (len == ll) ? 0 : 1;
+ else if (len == ll) /* l is finished? */
+ return -1; /* l is smaller than r (because r is not finished) */
+ /* both strings longer than `len'; go on comparing (after the `\0') */
+ len++;
+ l += len; ll -= len; r += len; lr -= len;
+ }
+ }
+}
+
+
+int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) {
+ int res;
+ if (ttype(l) != ttype(r))
+ return luaG_ordererror(L, l, r);
+ else if (ttisnumber(l))
+ return nvalue(l) < nvalue(r);
+ else if (ttisstring(l))
+ return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0;
+ else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
+ return res;
+ return luaG_ordererror(L, l, r);
+}
+
+
+static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) {
+ int res;
+ if (ttype(l) != ttype(r))
+ return luaG_ordererror(L, l, r);
+ else if (ttisnumber(l))
+ return nvalue(l) <= nvalue(r);
+ else if (ttisstring(l))
+ return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0;
+ else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */
+ return res;
+ else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */
+ return !res;
+ return luaG_ordererror(L, l, r);
+}
+
+
+int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) {
+ const TObject *tm;
+ lua_assert(ttype(t1) == ttype(t2));
+ switch (ttype(t1)) {
+ case LUA_TNIL: return 1;
+ case LUA_TNUMBER: return nvalue(t1) == nvalue(t2);
+ case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
+ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
+ case LUA_TUSERDATA: {
+ if (uvalue(t1) == uvalue(t2)) return 1;
+ tm = get_compTM(L, uvalue(t1)->uv.metatable, uvalue(t2)->uv.metatable,
+ TM_EQ);
+ break; /* will try TM */
+ }
+ case LUA_TTABLE: {
+ if (hvalue(t1) == hvalue(t2)) return 1;
+ tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
+ break; /* will try TM */
+ }
+ default: return gcvalue(t1) == gcvalue(t2);
+ }
+ if (tm == NULL) return 0; /* no TM? */
+ callTMres(L, tm, t1, t2); /* call TM */
+ return !l_isfalse(L->top);
+}
+
+
+void luaV_concat (lua_State *L, int total, int last) {
+ do {
+ StkId top = L->base + last + 1;
+ int n = 2; /* number of elements handled in this pass (at least 2) */
+ if (!tostring(L, top-2) || !tostring(L, top-1)) {
+ if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
+ luaG_concaterror(L, top-2, top-1);
+ } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */
+ /* at least two string values; get as many as possible */
+ lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) +
+ cast(lu_mem, tsvalue(top-2)->tsv.len);
+ char *buffer;
+ int i;
+ while (n < total && tostring(L, top-n-1)) { /* collect total length */
+ tl += tsvalue(top-n-1)->tsv.len;
+ n++;
+ }
+ if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow");
+ buffer = luaZ_openspace(L, &G(L)->buff, tl);
+ tl = 0;
+ for (i=n; i>0; i--) { /* concat all strings */
+ size_t l = tsvalue(top-i)->tsv.len;
+ memcpy(buffer+tl, svalue(top-i), l);
+ tl += l;
+ }
+ setsvalue2s(top-n, luaS_newlstr(L, buffer, tl));
+ }
+ total -= n-1; /* got `n' strings to create 1 new */
+ last -= n-1;
+ } while (total > 1); /* repeat until only 1 result left */
+}
+
+
+static void Arith (lua_State *L, StkId ra,
+ const TObject *rb, const TObject *rc, TMS op) {
+ TObject tempb, tempc;
+ const TObject *b, *c;
+ if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
+ (c = luaV_tonumber(rc, &tempc)) != NULL) {
+ switch (op) {
+ case TM_ADD: setnvalue(ra, nvalue(b) + nvalue(c)); break;
+ case TM_SUB: setnvalue(ra, nvalue(b) - nvalue(c)); break;
+ case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break;
+ case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break;
+ case TM_POW: {
+ const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]);
+ ptrdiff_t res = savestack(L, ra);
+ if (!ttisfunction(f))
+ luaG_runerror(L, "`__pow' (`^' operator) is not a function");
+ callTMres(L, f, b, c);
+ ra = restorestack(L, res); /* previous call may change stack */
+ setobjs2s(ra, L->top);
+ break;
+ }
+ default: lua_assert(0); break;
+ }
+ }
+ else if (!call_binTM(L, rb, rc, ra, op))
+ luaG_aritherror(L, rb, rc);
+}
+
+
+
+/*
+** some macros for common tasks in `luaV_execute'
+*/
+
+#define runtime_check(L, c) { if (!(c)) return 0; }
+
+#define RA(i) (base+GETARG_A(i))
+/* to be used after possible stack reallocation */
+#define XRA(i) (L->base+GETARG_A(i))
+#define RB(i) (base+GETARG_B(i))
+#define RKB(i) ((GETARG_B(i) < MAXSTACK) ? RB(i) : k+GETARG_B(i)-MAXSTACK)
+#define RC(i) (base+GETARG_C(i))
+#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? RC(i) : k+GETARG_C(i)-MAXSTACK)
+#define KBx(i) (k+GETARG_Bx(i))
+
+
+#define dojump(pc, i) ((pc) += (i))
+
+
+StkId luaV_execute (lua_State *L) {
+ LClosure *cl;
+ TObject *k;
+ const Instruction *pc;
+ callentry: /* entry point when calling new functions */
+ L->ci->u.l.pc = &pc;
+ if (L->hookmask & LUA_MASKCALL)
+ luaD_callhook(L, LUA_HOOKCALL, -1);
+ retentry: /* entry point when returning to old functions */
+ lua_assert(L->ci->state == CI_SAVEDPC ||
+ L->ci->state == (CI_SAVEDPC | CI_CALLING));
+ L->ci->state = CI_HASFRAME; /* activate frame */
+ pc = L->ci->u.l.savedpc;
+ cl = &clvalue(L->base - 1)->l;
+ k = cl->p->k;
+ /* main loop of interpreter */
+ for (;;) {
+ const Instruction i = *pc++;
+ StkId base, ra;
+ if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
+ (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
+ traceexec(L);
+ if (L->ci->state & CI_YIELD) { /* did hook yield? */
+ L->ci->u.l.savedpc = pc - 1;
+ L->ci->state = CI_YIELD | CI_SAVEDPC;
+ return NULL;
+ }
+ if (L->ci->state & CI_BREAK) { /* did hook break? */
+ luaG_runerror(L, "breaking");
+ L->ci->state &= ~CI_BREAK;
+ }
+ }
+ /* warning!! several calls may realloc the stack and invalidate `ra' */
+ base = L->base;
+ ra = RA(i);
+ lua_assert(L->ci->state & CI_HASFRAME);
+ lua_assert(base == L->ci->base);
+ lua_assert(L->top <= L->stack + L->stacksize && L->top >= base);
+ lua_assert(L->top == L->ci->top ||
+ GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL ||
+ GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO);
+ switch (GET_OPCODE(i)) {
+ case OP_MOVE: {
+ setobjs2s(ra, RB(i));
+ break;
+ }
+ case OP_LOADK: {
+ setobj2s(ra, KBx(i));
+ break;
+ }
+ case OP_LOADBOOL: {
+ setbvalue(ra, GETARG_B(i));
+ if (GETARG_C(i)) pc++; /* skip next instruction (if C) */
+ break;
+ }
+ case OP_LOADNIL: {
+ TObject *rb = RB(i);
+ do {
+ setnilvalue(rb--);
+ } while (rb >= ra);
+ break;
+ }
+ case OP_GETUPVAL: {
+ int b = GETARG_B(i);
+ setobj2s(ra, cl->upvals[b]->v);
+ break;
+ }
+ case OP_GETGLOBAL: {
+ TObject *rb = KBx(i);
+ const TObject *v;
+ lua_assert(ttisstring(rb) && ttistable(&cl->g));
+ v = luaH_getstr(hvalue(&cl->g), tsvalue(rb));
+ if (!ttisnil(v)) { setobj2s(ra, v); }
+ else
+ setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0));
+ break;
+ }
+ case OP_GETTABLE: {
+ StkId rb = RB(i);
+ TObject *rc = RKC(i);
+ if (ttistable(rb)) {
+ const TObject *v = luaH_get(hvalue(rb), rc);
+ if (!ttisnil(v)) { setobj2s(ra, v); }
+ else
+ setobj2s(XRA(i), luaV_index(L, rb, rc, 0));
+ }
+ else
+ setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0));
+ break;
+ }
+ case OP_SETGLOBAL: {
+ lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g));
+ luaV_settable(L, &cl->g, KBx(i), ra);
+ break;
+ }
+ case OP_SETUPVAL: {
+ int b = GETARG_B(i);
+ setobj(cl->upvals[b]->v, ra); /* write barrier */
+ break;
+ }
+ case OP_SETTABLE: {
+ luaV_settable(L, ra, RKB(i), RKC(i));
+ break;
+ }
+ case OP_NEWTABLE: {
+ int b = GETARG_B(i);
+ b = fb2int(b);
+ sethvalue(ra, luaH_new(L, b, GETARG_C(i)));
+ luaC_checkGC(L);
+ break;
+ }
+ case OP_SELF: {
+ StkId rb = RB(i);
+ TObject *rc = RKC(i);
+ runtime_check(L, ttisstring(rc));
+ setobjs2s(ra+1, rb);
+ if (ttistable(rb)) {
+ const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc));
+ if (!ttisnil(v)) { setobj2s(ra, v); }
+ else
+ setobj2s(XRA(i), luaV_index(L, rb, rc, 0));
+ }
+ else
+ setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0));
+ break;
+ }
+ case OP_ADD: {
+ TObject *rb = RKB(i);
+ TObject *rc = RKC(i);
+ if (ttisnumber(rb) && ttisnumber(rc)) {
+ setnvalue(ra, nvalue(rb) + nvalue(rc));
+ }
+ else
+ Arith(L, ra, rb, rc, TM_ADD);
+ break;
+ }
+ case OP_SUB: {
+ TObject *rb = RKB(i);
+ TObject *rc = RKC(i);
+ if (ttisnumber(rb) && ttisnumber(rc)) {
+ setnvalue(ra, nvalue(rb) - nvalue(rc));
+ }
+ else
+ Arith(L, ra, rb, rc, TM_SUB);
+ break;
+ }
+ case OP_MUL: {
+ TObject *rb = RKB(i);
+ TObject *rc = RKC(i);
+ if (ttisnumber(rb) && ttisnumber(rc)) {
+ setnvalue(ra, nvalue(rb) * nvalue(rc));
+ }
+ else
+ Arith(L, ra, rb, rc, TM_MUL);
+ break;
+ }
+ case OP_DIV: {
+ TObject *rb = RKB(i);
+ TObject *rc = RKC(i);
+ if (ttisnumber(rb) && ttisnumber(rc)) {
+ setnvalue(ra, nvalue(rb) / nvalue(rc));
+ }
+ else
+ Arith(L, ra, rb, rc, TM_DIV);
+ break;
+ }
+ case OP_POW: {
+ Arith(L, ra, RKB(i), RKC(i), TM_POW);
+ break;
+ }
+ case OP_UNM: {
+ const TObject *rb = RB(i);
+ TObject temp;
+ if (tonumber(rb, &temp)) {
+ setnvalue(ra, -nvalue(rb));
+ }
+ else {
+ setnilvalue(&temp);
+ if (!call_binTM(L, RB(i), &temp, ra, TM_UNM))
+ luaG_aritherror(L, RB(i), &temp);
+ }
+ break;
+ }
+ case OP_NOT: {
+ int res = l_isfalse(RB(i)); /* next assignment may change this value */
+ setbvalue(ra, res);
+ break;
+ }
+ case OP_CONCAT: {
+ int b = GETARG_B(i);
+ int c = GETARG_C(i);
+ luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */
+ base = L->base;
+ setobjs2s(RA(i), base+b);
+ luaC_checkGC(L);
+ break;
+ }
+ case OP_JMP: {
+ dojump(pc, GETARG_sBx(i));
+ break;
+ }
+ case OP_EQ: {
+ if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++;
+ else dojump(pc, GETARG_sBx(*pc) + 1);
+ break;
+ }
+ case OP_LT: {
+ if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++;
+ else dojump(pc, GETARG_sBx(*pc) + 1);
+ break;
+ }
+ case OP_LE: {
+ if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++;
+ else dojump(pc, GETARG_sBx(*pc) + 1);
+ break;
+ }
+ case OP_TEST: {
+ TObject *rb = RB(i);
+ if (l_isfalse(rb) == GETARG_C(i)) pc++;
+ else {
+ setobjs2s(ra, rb);
+ dojump(pc, GETARG_sBx(*pc) + 1);
+ }
+ break;
+ }
+ case OP_CALL:
+ case OP_TAILCALL: {
+ StkId firstResult;
+ int b = GETARG_B(i);
+ int nresults;
+ if (b != 0) L->top = ra+b; /* else previous instruction set top */
+ nresults = GETARG_C(i) - 1;
+ firstResult = luaD_precall(L, ra);
+ if (firstResult) {
+ if (firstResult > L->top) { /* yield? */
+ lua_assert(L->ci->state == (CI_C | CI_YIELD));
+ (L->ci - 1)->u.l.savedpc = pc;
+ (L->ci - 1)->state = CI_SAVEDPC;
+ return NULL;
+ }
+ /* it was a C function (`precall' called it); adjust results */
+ luaD_poscall(L, nresults, firstResult);
+ if (nresults >= 0) L->top = L->ci->top;
+ }
+ else { /* it is a Lua function */
+ if (GET_OPCODE(i) == OP_CALL) { /* regular call? */
+ (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */
+ (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING);
+ }
+ else { /* tail call: put new frame in place of previous one */
+ int aux;
+ base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */
+ ra = RA(i);
+ if (L->openupval) luaF_close(L, base);
+ for (aux = 0; ra+aux < L->top; aux++) /* move frame down */
+ setobjs2s(base+aux-1, ra+aux);
+ (L->ci - 1)->top = L->top = base+aux; /* correct top */
+ lua_assert(L->ci->state & CI_SAVEDPC);
+ (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc;
+ (L->ci - 1)->u.l.tailcalls++; /* one more call lost */
+ (L->ci - 1)->state = CI_SAVEDPC;
+ L->ci--; /* remove new frame */
+ L->base = L->ci->base;
+ }
+ goto callentry;
+ }
+ break;
+ }
+ case OP_RETURN: {
+ CallInfo *ci = L->ci - 1; /* previous function frame */
+ int b = GETARG_B(i);
+ if (b != 0) L->top = ra+b-1;
+ lua_assert(L->ci->state & CI_HASFRAME);
+ if (L->openupval) luaF_close(L, base);
+ L->ci->state = CI_SAVEDPC; /* deactivate current function */
+ L->ci->u.l.savedpc = pc;
+ /* previous function was running `here'? */
+ if (!(ci->state & CI_CALLING)) {
+ lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc);
+ return ra; /* no: return */
+ }
+ else { /* yes: continue its execution */
+ int nresults;
+ lua_assert(ci->u.l.pc == &pc &&
+ ttisfunction(ci->base - 1) &&
+ (ci->state & CI_SAVEDPC));
+ lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL);
+ nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1;
+ luaD_poscall(L, nresults, ra);
+ if (nresults >= 0) L->top = L->ci->top;
+ goto retentry;
+ }
+ }
+ case OP_FORLOOP: {
+ lua_Number step, idx, limit;
+ const TObject *plimit = ra+1;
+ const TObject *pstep = ra+2;
+ if (!ttisnumber(ra))
+ luaG_runerror(L, "`for' initial value must be a number");
+ if (!tonumber(plimit, ra+1))
+ luaG_runerror(L, "`for' limit must be a number");
+ if (!tonumber(pstep, ra+2))
+ luaG_runerror(L, "`for' step must be a number");
+ step = nvalue(pstep);
+ idx = nvalue(ra) + step; /* increment index */
+ limit = nvalue(plimit);
+ if (step > 0 ? idx <= limit : idx >= limit) {
+ dojump(pc, GETARG_sBx(i)); /* jump back */
+ chgnvalue(ra, idx); /* update index */
+ }
+ break;
+ }
+ case OP_TFORLOOP: {
+ int nvar = GETARG_C(i) + 1;
+ StkId cb = ra + nvar + 2; /* call base */
+ setobjs2s(cb, ra);
+ setobjs2s(cb+1, ra+1);
+ setobjs2s(cb+2, ra+2);
+ L->top = cb+3; /* func. + 2 args (state and index) */
+ luaD_call(L, cb, nvar);
+ L->top = L->ci->top;
+ ra = XRA(i) + 2; /* final position of first result */
+ cb = ra + nvar;
+ do { /* move results to proper positions */
+ nvar--;
+ setobjs2s(ra+nvar, cb+nvar);
+ } while (nvar > 0);
+ if (ttisnil(ra)) /* break loop? */
+ pc++; /* skip jump (break loop) */
+ else
+ dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */
+ break;
+ }
+ case OP_TFORPREP: { /* for compatibility only */
+ if (ttistable(ra)) {
+ setobjs2s(ra+1, ra);
+ setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next")));
+ }
+ dojump(pc, GETARG_sBx(i));
+ break;
+ }
+ case OP_SETLIST:
+ case OP_SETLISTO: {
+ int bc;
+ int n;
+ Table *h;
+ runtime_check(L, ttistable(ra));
+ h = hvalue(ra);
+ bc = GETARG_Bx(i);
+ if (GET_OPCODE(i) == OP_SETLIST)
+ n = (bc&(LFIELDS_PER_FLUSH-1)) + 1;
+ else {
+ n = L->top - ra - 1;
+ L->top = L->ci->top;
+ }
+ bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */
+ for (; n > 0; n--)
+ setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */
+ break;
+ }
+ case OP_CLOSE: {
+ luaF_close(L, ra);
+ break;
+ }
+ case OP_CLOSURE: {
+ Proto *p;
+ Closure *ncl;
+ int nup, j;
+ p = cl->p->p[GETARG_Bx(i)];
+ nup = p->nups;
+ ncl = luaF_newLclosure(L, nup, &cl->g);
+ ncl->l.p = p;
+ for (j=0; j<nup; j++, pc++) {
+ if (GET_OPCODE(*pc) == OP_GETUPVAL)
+ ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
+ else {
+ lua_assert(GET_OPCODE(*pc) == OP_MOVE);
+ ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
+ }
+ }
+ setclvalue(ra, ncl);
+ luaC_checkGC(L);
+ break;
+ }
+ }
+ }
+}
+
diff --git a/lib/lua/src/lzio.c b/lib/lua/src/lzio.c index 6f52ec6..e3aefa0 100644 --- a/lib/lua/src/lzio.c +++ b/lib/lua/src/lzio.c @@ -1,81 +1,81 @@ -/* -** $Id: lzio.c,v 1.2 2003-12-11 16:53:30 pixel Exp $ -** a generic input stream interface -** See Copyright Notice in lua.h -*/ - - -#include <string.h> - -#define lzio_c - -#include "lua.h" - -#include "llimits.h" -#include "lmem.h" -#include "lzio.h" - - -int luaZ_fill (ZIO *z) { - size_t size; - const char *buff = z->reader(NULL, z->data, &size); - if (buff == NULL || size == 0) return EOZ; - z->n = size - 1; - z->p = buff; - return char2int(*(z->p++)); -} - - -int luaZ_lookahead (ZIO *z) { - if (z->n == 0) { - int c = luaZ_fill(z); - if (c == EOZ) return c; - z->n++; - z->p--; - } - return char2int(*z->p); -} - - -void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) { - z->reader = reader; - z->data = data; - z->name = name; - z->n = 0; - z->p = NULL; -} - - -/* --------------------------------------------------------------- read --- */ -size_t luaZ_read (ZIO *z, void *b, size_t n) { - while (n) { - size_t m; - if (z->n == 0) { - if (luaZ_fill(z) == EOZ) - return n; /* return number of missing bytes */ - else { - ++z->n; /* filbuf removed first byte; put back it */ - --z->p; - } - } - m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ - memcpy(b, z->p, m); - z->n -= m; - z->p += m; - b = (char *)b + m; - n -= m; - } - return 0; -} - -/* ------------------------------------------------------------------------ */ -char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { - if (n > buff->buffsize) { - if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaM_reallocvector(L, buff->buffer, buff->buffsize, n, char); - buff->buffsize = n; - } - return buff->buffer; -} - - +/*
+** $Id: lzio.c,v 1.3 2004-11-27 21:35:20 pixel Exp $
+** a generic input stream interface
+** See Copyright Notice in lua.h
+*/
+
+
+#include <string.h>
+
+#define lzio_c
+
+#include "lua.h"
+
+#include "llimits.h"
+#include "lmem.h"
+#include "lzio.h"
+
+
+int luaZ_fill (ZIO *z) {
+ size_t size;
+ const char *buff = z->reader(NULL, z->data, &size);
+ if (buff == NULL || size == 0) return EOZ;
+ z->n = size - 1;
+ z->p = buff;
+ return char2int(*(z->p++));
+}
+
+
+int luaZ_lookahead (ZIO *z) {
+ if (z->n == 0) {
+ int c = luaZ_fill(z);
+ if (c == EOZ) return c;
+ z->n++;
+ z->p--;
+ }
+ return char2int(*z->p);
+}
+
+
+void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) {
+ z->reader = reader;
+ z->data = data;
+ z->name = name;
+ z->n = 0;
+ z->p = NULL;
+}
+
+
+/* --------------------------------------------------------------- read --- */
+size_t luaZ_read (ZIO *z, void *b, size_t n) {
+ while (n) {
+ size_t m;
+ if (z->n == 0) {
+ if (luaZ_fill(z) == EOZ)
+ return n; /* return number of missing bytes */
+ else {
+ ++z->n; /* filbuf removed first byte; put back it */
+ --z->p;
+ }
+ }
+ m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
+ memcpy(b, z->p, m);
+ z->n -= m;
+ z->p += m;
+ b = (char *)b + m;
+ n -= m;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
+ if (n > buff->buffsize) {
+ if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
+ luaM_reallocvector(L, buff->buffer, buff->buffsize, n, char);
+ buff->buffsize = n;
+ }
+ return buff->buffer;
+}
+
+
diff --git a/lib/zlib/src/adler32.c b/lib/zlib/src/adler32.c index f900609..eeffe9b 100644 --- a/lib/zlib/src/adler32.c +++ b/lib/zlib/src/adler32.c @@ -1,48 +1,48 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: adler32.c,v 1.1 2003-09-14 18:16:26 pixel Exp $ */ - -#include "zlib.h" - -#define BASE 65521L /* 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) {s1 += buf[i]; s2 += s1;} -#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); - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} +/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c,v 1.2 2004-11-27 21:35:22 pixel Exp $ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* 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) {s1 += buf[i]; s2 += s1;}
+#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);
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
diff --git a/lib/zlib/src/compress.c b/lib/zlib/src/compress.c index 19e54d1..d5e2d4b 100644 --- a/lib/zlib/src/compress.c +++ b/lib/zlib/src/compress.c @@ -1,68 +1,68 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: compress.c,v 1.1 2003-09-14 18:16:26 pixel Exp $ */ - -#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); -} +/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: compress.c,v 1.2 2004-11-27 21:35:22 pixel Exp $ */
+
+#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);
+}
diff --git a/lib/zlib/src/crc32.c b/lib/zlib/src/crc32.c index b869166..434d6f9 100644 --- a/lib/zlib/src/crc32.c +++ b/lib/zlib/src/crc32.c @@ -1,162 +1,162 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: crc32.c,v 1.1 2003-09-14 18:16:26 pixel Exp $ */ - -#include "zlib.h" - -#define local static - -#ifdef DYNAMIC_CRC_TABLE - -local int crc_table_empty = 1; -local uLongf crc_table[256]; -local void make_crc_table OF((void)); - -/* - Generate a table 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 table is simply the CRC of all possible eight bit values. This is all - the information needed to generate CRC's on data a byte at a time for all - combinations of CRC register values and incoming bytes. -*/ -local void make_crc_table() -{ - uLong c; - int n, k; - uLong poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* make exclusive-or pattern from polynomial (0xedb88320L) */ - poly = 0L; - for (n = 0; n < sizeof(p)/sizeof(Byte); n++) - poly |= 1L << (31 - p[n]); - - for (n = 0; n < 256; n++) - { - c = (uLong)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[n] = c; - } - crc_table_empty = 0; -} -#else -/* ======================================================================== - * Table of CRC-32's of all single-byte values (made by make_crc_table) - */ -local const uLongf crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; -#endif - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const uLongf * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) make_crc_table(); -#endif - return (const uLongf *)crc_table; -} - -/* ========================================================================= */ -#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); - -/* ========================================================================= */ -uLong ZEXPORT crc32(crc, buf, len) - uLong crc; - const Bytef *buf; - uInt len; -{ - if (buf == Z_NULL) return 0L; -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif - crc = crc ^ 0xffffffffL; - while (len >= 8) - { - DO8(buf); - len -= 8; - } - if (len) do { - DO1(buf); - } while (--len); - return crc ^ 0xffffffffL; -} +/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: crc32.c,v 1.2 2004-11-27 21:35:22 pixel Exp $ */
+
+#include "zlib.h"
+
+#define local static
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local int crc_table_empty = 1;
+local uLongf crc_table[256];
+local void make_crc_table OF((void));
+
+/*
+ Generate a table 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 table is simply the CRC of all possible eight bit values. This is all
+ the information needed to generate CRC's on data a byte at a time for all
+ combinations of CRC register values and incoming bytes.
+*/
+local void make_crc_table()
+{
+ uLong c;
+ int n, k;
+ uLong poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* make exclusive-or pattern from polynomial (0xedb88320L) */
+ poly = 0L;
+ for (n = 0; n < sizeof(p)/sizeof(Byte); n++)
+ poly |= 1L << (31 - p[n]);
+
+ for (n = 0; n < 256; n++)
+ {
+ c = (uLong)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[n] = c;
+ }
+ crc_table_empty = 0;
+}
+#else
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local const uLongf crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+#endif
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const uLongf * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty) make_crc_table();
+#endif
+ return (const uLongf *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+uLong ZEXPORT crc32(crc, buf, len)
+ uLong crc;
+ const Bytef *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0L;
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif
+ crc = crc ^ 0xffffffffL;
+ while (len >= 8)
+ {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) do {
+ DO1(buf);
+ } while (--len);
+ return crc ^ 0xffffffffL;
+}
diff --git a/lib/zlib/src/deflate.c b/lib/zlib/src/deflate.c index 7a5eb77..a891418 100644 --- a/lib/zlib/src/deflate.c +++ b/lib/zlib/src/deflate.c @@ -1,1350 +1,1350 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2002 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 ftp://ds.internic.net/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: deflate.c,v 1.1 2003-09-14 18:16:26 pixel Exp $ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.1.4 Copyright 1995-2002 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)); -local block_state deflate_slow OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#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; - -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}, /* maximum 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}}; /* maximum compression */ - -/* 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 */ - -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ - -/* =========================================================================== - * 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)]), \ - s->prev[(str) & s->w_mask] = match_head = 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 noheader = 0; - 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 == Z_NULL) { - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; - } - if (strm->zfree == Z_NULL) strm->zfree = zcfree; - - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#ifdef FASTEST - level = 1; -#endif - - if (windowBits < 0) { /* undocumented feature: suppress zlib header */ - noheader = 1; - windowBits = -windowBits; - } - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - 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->noheader = noheader; - 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) { - 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->status != INIT_STATE) return Z_STREAM_ERROR; - - s = strm->state; - strm->adler = adler32(strm->adler, dictionary, dictLength); - - if (length < MIN_MATCH) return Z_OK; - if (length > MAX_DIST(s)) { - length = MAX_DIST(s); -#ifndef USE_DICT_HEAD - dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif - } - 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 == Z_NULL || strm->zfree == Z_NULL) 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->noheader < 0) { - s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ - } - s->status = s->noheader ? BUSY_STATE : INIT_STATE; - strm->adler = 1; - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - lm_init(s); - - 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; - - if (level == Z_DEFAULT_COMPRESSION) { - level = 6; - } - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - 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; -} - -/* ========================================================================= - * 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 zlib header */ - if (s->status == INIT_STATE) { - - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags = (s->level-1) >> 1; - - if (level_flags > 3) 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 = 1L; - } - - /* 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_BUFF_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->noheader) return Z_STREAM_END; - - /* Write the zlib trailer (adler32) */ - 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. - */ - s->noheader = -1; /* 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 != 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; - - *dest = *source; - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - *ds = *ss; - 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 -} - -/* =========================================================================== - * 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->noheader) { - strm->adler = adler32(strm->adler, strm->next_in, len); - } - 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; -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -} - -/* =========================================================================== - * 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. - */ -#ifndef FASTEST -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: - */ -#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; -} - -#else /* FASTEST */ -/* --------------------------------------------------------------------------- - * Optimized version for level == 1 only - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return len <= s->lookahead ? len : s->lookahead; -} -#endif /* FASTEST */ -#endif /* ASMV */ - -#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 - -/* =========================================================================== - * 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 (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 - * and lookahead == 1 (input done one 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. - */ - } else if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif - more += wsize; - } - if (s->strm->avail_in == 0) 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). - */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in hash 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; -} - -/* =========================================================================== - * 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->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED || - (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR))) { - - /* 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; -} +/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2002 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 ftp://ds.internic.net/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: deflate.c,v 1.2 2004-11-27 21:35:22 pixel Exp $ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.1.4 Copyright 1995-2002 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));
+local block_state deflate_slow OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#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;
+
+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}, /* maximum 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}}; /* maximum compression */
+
+/* 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 */
+
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+
+/* ===========================================================================
+ * 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)]), \
+ s->prev[(str) & s->w_mask] = match_head = 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 noheader = 0;
+ 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 == Z_NULL) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#ifdef FASTEST
+ level = 1;
+#endif
+
+ if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+ 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->noheader = noheader;
+ 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) {
+ 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->status != INIT_STATE) return Z_STREAM_ERROR;
+
+ s = strm->state;
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+ }
+ 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 == Z_NULL || strm->zfree == Z_NULL) 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->noheader < 0) {
+ s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+ }
+ s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+ strm->adler = 1;
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ 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;
+
+ if (level == Z_DEFAULT_COMPRESSION) {
+ level = 6;
+ }
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ 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;
+}
+
+/* =========================================================================
+ * 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 zlib header */
+ if (s->status == INIT_STATE) {
+
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags = (s->level-1) >> 1;
+
+ if (level_flags > 3) 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 = 1L;
+ }
+
+ /* 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_BUFF_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->noheader) return Z_STREAM_END;
+
+ /* Write the zlib trailer (adler32) */
+ 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.
+ */
+ s->noheader = -1; /* 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 != 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;
+
+ *dest = *source;
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ *ds = *ss;
+ 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
+}
+
+/* ===========================================================================
+ * 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->noheader) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+ 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;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * 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.
+ */
+#ifndef FASTEST
+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:
+ */
+#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;
+}
+
+#else /* FASTEST */
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return len <= s->lookahead ? len : s->lookahead;
+}
+#endif /* FASTEST */
+#endif /* ASMV */
+
+#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
+
+/* ===========================================================================
+ * 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 (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
+ * and lookahead == 1 (input done one 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.
+ */
+ } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) 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).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY) {
+ s->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in hash 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;
+}
+
+/* ===========================================================================
+ * 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->match_length = longest_match (s, hash_head);
+ }
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+ (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR))) {
+
+ /* 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;
+}
diff --git a/lib/zlib/src/gzio.c b/lib/zlib/src/gzio.c index fed1ffa..4e5a432 100644 --- a/lib/zlib/src/gzio.c +++ b/lib/zlib/src/gzio.c @@ -1,879 +1,879 @@ -/* gzio.c -- IO on .gz files - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Compile this file with -DNO_DEFLATE to avoid the compression code. - */ - -/* @(#) $Id: gzio.c,v 1.3 2003-12-27 01:51:41 pixel Exp $ */ - -#include <stdio.h> - -#include "zutil.h" - -struct internal_state {int dummy;}; /* for buggy compilers */ - -#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 - -#define ALLOC(size) malloc(size) -#define TRYFREE(p) {if (p) free(p);} - -static int 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' */ - long startpos; /* start of compressed data in file (header skipped) */ -} 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 return 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->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 { - *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_DEFLATE - 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->startpos = 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 - * startpos anyway in write mode, so this initialization is not - * necessary. - */ - } else { - check_header(s); /* skip the .gz header */ - s->startpos = (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[20]; - - 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 = 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; - - /* Check the gzip magic header */ - for (len = 0; len < 2; len++) { - c = get_byte(s); - if (c != gz_magic[len]) { - if (len != 0) s->stream.avail_in++, s->stream.next_in--; - if (c != EOF) { - s->stream.avail_in++, s->stream.next_in--; - s->transparent = 1; - } - s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; - return; - } - } - 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_DEFLATE - 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; - - 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 -= fread(next_out, 1, s->stream.avail_out, - s->file); - } - len -= s->stream.avail_out; - s->stream.total_in += (uLong)len; - s->stream.total_out += (uLong)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 = 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->z_err = inflate(&(s->stream), Z_NO_FLUSH); - - 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->stream.total_out) in case of - * concatenated .gz files. Check for such files: - */ - check_header(s); - if (s->z_err == Z_OK) { - uLong total_in = s->stream.total_in; - uLong total_out = s->stream.total_out; - - inflateReset(&(s->stream)); - s->stream.total_in = total_in; - s->stream.total_out = total_out; - 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)); - - 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; -} - - -/* =========================================================================== - 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_DEFLATE -/* =========================================================================== - 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; - cvoidp 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->z_err = deflate(&(s->stream), Z_NO_FLUSH); - 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; - - va_start(va, format); -#ifdef HAS_vsnprintf - (void)vsnprintf(buf, sizeof(buf), format, va); -#else - (void)vsprintf(buf, format, va); -#endif - va_end(va); - len = strlen(buf); /* some *sprintf don't return the nb of bytes written */ - if (len <= 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; - -#ifdef HAS_snprintf - 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); -#else - sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -#endif - len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */ - if (len <= 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) - return Z_STREAM_ERROR; - else - if (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->z_err = deflate(&(s->stream), flush); - - /* 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_DEFLATE */ - -/* =========================================================================== - 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_DEFLATE - return -1L; -#else - if (whence == SEEK_SET) { - offset -= s->stream.total_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 */ - 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 (z_off_t)s->stream.total_in; -#endif - } - /* Rest of function is for reading only */ - - /* compute absolute position */ - if (whence == SEEK_CUR) { - offset += s->stream.total_out; - } - if (offset < 0) return -1L; - - if (s->transparent) { - /* map to fseek */ - s->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; - - s->stream.total_in = s->stream.total_out = (uLong)offset; - return offset; - } - - /* For a negative seek, rewind and use positive seek */ - if ((uLong)offset >= s->stream.total_out) { - offset -= s->stream.total_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); - } - 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 (z_off_t)s->stream.total_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->stream.avail_in = 0; - s->stream.next_in = s->inbuf; - s->crc = crc32(0L, Z_NULL, 0); - - if (s->startpos == 0) { /* not a compressed file */ - rewind(s->file); - return 0; - } - - (void) inflateReset(&s->stream); - return fseek(s->file, s->startpos, 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; - - return (s == NULL || s->mode != 'r') ? 0 : s->z_eof; -} - -/* =========================================================================== - 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; -{ - int err; - gz_stream *s = (gz_stream*)file; - - if (s == NULL) return Z_STREAM_ERROR; - - if (s->mode == 'w') { -#ifdef NO_DEFLATE - return Z_STREAM_ERROR; -#else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); - - putLong (s->file, s->crc); - putLong (s->file, s->stream.total_in); -#endif - } - return destroy((gz_stream*)file); -} - -/* =========================================================================== - Returns the error message for the last error which occured on the - given compressed file. errnum is set to zlib error number. If an - error occured 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); - strcpy(s->msg, s->path); - strcat(s->msg, ": "); - strcat(s->msg, m); - return (const char*)s->msg; -} +/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_DEFLATE to avoid the compression code.
+ */
+
+/* @(#) $Id: gzio.c,v 1.4 2004-11-27 21:35:22 pixel Exp $ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#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
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int 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' */
+ long startpos; /* start of compressed data in file (header skipped) */
+} 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 return 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->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 {
+ *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_DEFLATE
+ 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->startpos = 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
+ * startpos anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->startpos = (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[20];
+
+ 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 = 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;
+
+ /* Check the gzip magic header */
+ for (len = 0; len < 2; len++) {
+ c = get_byte(s);
+ if (c != gz_magic[len]) {
+ if (len != 0) s->stream.avail_in++, s->stream.next_in--;
+ if (c != EOF) {
+ s->stream.avail_in++, s->stream.next_in--;
+ s->transparent = 1;
+ }
+ s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
+ return;
+ }
+ }
+ 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_DEFLATE
+ 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;
+
+ 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 -= fread(next_out, 1, s->stream.avail_out,
+ s->file);
+ }
+ len -= s->stream.avail_out;
+ s->stream.total_in += (uLong)len;
+ s->stream.total_out += (uLong)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 = 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->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+
+ 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->stream.total_out) in case of
+ * concatenated .gz files. Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ uLong total_in = s->stream.total_in;
+ uLong total_out = s->stream.total_out;
+
+ inflateReset(&(s->stream));
+ s->stream.total_in = total_in;
+ s->stream.total_out = total_out;
+ 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));
+
+ 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;
+}
+
+
+/* ===========================================================================
+ 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_DEFLATE
+/* ===========================================================================
+ 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;
+ cvoidp 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->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ 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;
+
+ va_start(va, format);
+#ifdef HAS_vsnprintf
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+#else
+ (void)vsprintf(buf, format, va);
+#endif
+ va_end(va);
+ len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
+ if (len <= 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;
+
+#ifdef HAS_snprintf
+ 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);
+#else
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#endif
+ len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */
+ if (len <= 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)
+ return Z_STREAM_ERROR;
+ else
+ if (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->z_err = deflate(&(s->stream), flush);
+
+ /* 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_DEFLATE */
+
+/* ===========================================================================
+ 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_DEFLATE
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->stream.total_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 */
+ 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 (z_off_t)s->stream.total_in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->stream.total_out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->stream.total_in = s->stream.total_out = (uLong)offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if ((uLong)offset >= s->stream.total_out) {
+ offset -= s->stream.total_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);
+ }
+ 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 (z_off_t)s->stream.total_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->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+
+ if (s->startpos == 0) { /* not a compressed file */
+ rewind(s->file);
+ return 0;
+ }
+
+ (void) inflateReset(&s->stream);
+ return fseek(s->file, s->startpos, 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;
+
+ return (s == NULL || s->mode != 'r') ? 0 : s->z_eof;
+}
+
+/* ===========================================================================
+ 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;
+{
+ int err;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_DEFLATE
+ return Z_STREAM_ERROR;
+#else
+ err = do_flush (file, Z_FINISH);
+ if (err != Z_OK) return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, s->stream.total_in);
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+/* ===========================================================================
+ Returns the error message for the last error which occured on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occured 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);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
diff --git a/lib/zlib/src/infblock.c b/lib/zlib/src/infblock.c index dd7a6d4..943e849 100644 --- a/lib/zlib/src/infblock.c +++ b/lib/zlib/src/infblock.c @@ -1,403 +1,403 @@ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* Table for deflate from PKZIP's appnote.txt. */ -local const uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_streamp z; -uLongf *c; -{ - if (c != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens); - if (s->mode == CODES) - inflate_codes_free(s->sub.decode.codes, z); - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); - Tracev((stderr, "inflate: blocks reset\n")); -} - - -inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_streamp z; -check_func c; -uInt w; -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->hufts = - (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) - { - ZFREE(z, s); - return Z_NULL; - } - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s->hufts); - ZFREE(z, s); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Tracev((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, Z_NULL); - return s; -} - - -int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Tracev((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Tracev((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td, z); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BAD; - z->msg = (char*)"invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) - { - s->mode = BAD; - z->msg = (char*)"invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BAD; - z->msg = (char*)"too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, s->hufts, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - } - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->bits; - c = h->base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - z->msg = (char*)"invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, - s->hufts, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - { - ZFREE(z, s->sub.trees.blens); - s->mode = BAD; - } - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.codes = c; - } - ZFREE(z, s->sub.trees.blens); - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONE; - case DONE: - r = Z_STREAM_END; - LEAVE - case BAD: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -int inflate_blocks_free(s, z) -inflate_blocks_statef *s; -z_streamp z; -{ - inflate_blocks_reset(s, z, Z_NULL); - ZFREE(z, s->window); - ZFREE(z, s->hufts); - ZFREE(z, s); - Tracev((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - - -void inflate_set_dictionary(s, d, n) -inflate_blocks_statef *s; -const Bytef *d; -uInt n; -{ - zmemcpy(s->window, d, n); - s->read = s->write = s->window + n; -} - - -/* Returns true if inflate is currently at the end of a block generated - * by Z_SYNC_FLUSH or Z_FULL_FLUSH. - * IN assertion: s != Z_NULL - */ -int inflate_blocks_sync_point(s) -inflate_blocks_statef *s; -{ - return s->mode == LENS; -} +/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ if (c != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens);
+ if (s->mode == CODES)
+ inflate_codes_free(s->sub.decode.codes, z);
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+ Tracev((stderr, "inflate: blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->hufts =
+ (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+ {
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Tracev((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, Z_NULL);
+ return s;
+}
+
+
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Tracev((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BAD;
+ z->msg = (char*)"invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = BAD;
+ z->msg = (char*)"invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BAD;
+ z->msg = (char*)"too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, s->hufts, z);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ }
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->bits;
+ c = h->base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ z->msg = (char*)"invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td,
+ s->hufts, z);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ }
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.codes = c;
+ }
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONE;
+ case DONE:
+ r = Z_STREAM_END;
+ LEAVE
+ case BAD:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_blocks_reset(s, z, Z_NULL);
+ ZFREE(z, s->window);
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ Tracev((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt n;
+{
+ zmemcpy(s->window, d, n);
+ s->read = s->write = s->window + n;
+}
+
+
+/* Returns true if inflate is currently at the end of a block generated
+ * by Z_SYNC_FLUSH or Z_FULL_FLUSH.
+ * IN assertion: s != Z_NULL
+ */
+int inflate_blocks_sync_point(s)
+inflate_blocks_statef *s;
+{
+ return s->mode == LENS;
+}
diff --git a/lib/zlib/src/infcodes.c b/lib/zlib/src/infcodes.c index 9abe541..aa7b3a0 100644 --- a/lib/zlib/src/infcodes.c +++ b/lib/zlib/src/infcodes.c @@ -1,251 +1,251 @@ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" -#include "inffast.h" - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ -inflate_codes_mode; - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - inflate_codes_mode mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -z_streamp z; -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t + t->base; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = (char*)"invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ - f = q - c->sub.copy.dist; - while (f < s->window) /* modulo window size-"while" instead */ - f += s->end - s->window; /* of "if" handles invalid distances */ - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_streamp z; -{ - ZFREE(z, c); - Tracev((stderr, "inflate: codes free\n")); -} +/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ inflate_codes_mode mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+ f = q - c->sub.copy.dist;
+ while (f < s->window) /* modulo window size-"while" instead */
+ f += s->end - s->window; /* of "if" handles invalid distances */
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+ ZFREE(z, c);
+ Tracev((stderr, "inflate: codes free\n"));
+}
diff --git a/lib/zlib/src/inffast.c b/lib/zlib/src/inffast.c index aa7f1d4..655eaf0 100644 --- a/lib/zlib/src/inffast.c +++ b/lib/zlib/src/inffast.c @@ -1,183 +1,183 @@ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "infblock.h" -#include "infcodes.h" -#include "infutil.h" -#include "inffast.h" - -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}} -#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -inflate_blocks_statef *s; -z_streamp z; -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - r = q - d; - if (r < s->window) /* wrap if needed */ - { - do { - r += s->end - s->window; /* force pointer in window */ - } while (r < s->window); /* covers invalid distances */ - e = s->end - r; - if (c > e) - { - c -= e; /* wrapped copy */ - do { - *q++ = *r++; - } while (--e); - r = s->window; - do { - *q++ = *r++; - } while (--c); - } - else /* normal copy */ - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); - } - } - else /* normal copy */ - { - *q++ = *r++; c--; - *q++ = *r++; c--; - do { - *q++ = *r++; - } while (--c); - } - break; - } - else if ((e & 64) == 0) - { - t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop; - } - else - { - z->msg = (char*)"invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - t += t->base; - if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = (char*)"invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} +/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+#include "inffast.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}
+
+/* Called with number of bytes left to write in window at least 258
+ (the maximum string length) and number of input bytes available
+ at least ten. The ten bytes are six bytes for the longest length/
+ distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ uInt ml; /* mask for literal/length tree */
+ uInt md; /* mask for distance tree */
+ uInt c; /* bytes to copy */
+ uInt d; /* distance back to copy from */
+ Bytef *r; /* copy source pointer */
+
+ /* load input, output, bit values */
+ LOAD
+
+ /* initialize masks */
+ ml = inflate_mask[bl];
+ md = inflate_mask[bd];
+
+ /* do until not enough input or output space for fast loop */
+ do { /* assume called with m >= 258 && n >= 10 */
+ /* get literal/length code */
+ GRABBITS(20) /* max bits for literal/length code */
+ if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ continue;
+ }
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits for length */
+ e &= 15;
+ c = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * length %u\n", c));
+
+ /* decode distance base of block to copy */
+ GRABBITS(15); /* max bits for distance code */
+ e = (t = td + ((uInt)b & md))->exop;
+ do {
+ DUMPBITS(t->bits)
+ if (e & 16)
+ {
+ /* get extra bits to add to distance base */
+ e &= 15;
+ GRABBITS(e) /* get extra bits (up to 13) */
+ d = t->base + ((uInt)b & inflate_mask[e]);
+ DUMPBITS(e)
+ Tracevv((stderr, "inflate: * distance %u\n", d));
+
+ /* do the copy */
+ m -= c;
+ r = q - d;
+ if (r < s->window) /* wrap if needed */
+ {
+ do {
+ r += s->end - s->window; /* force pointer in window */
+ } while (r < s->window); /* covers invalid distances */
+ e = s->end - r;
+ if (c > e)
+ {
+ c -= e; /* wrapped copy */
+ do {
+ *q++ = *r++;
+ } while (--e);
+ r = s->window;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ else /* normal copy */
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ }
+ else /* normal copy */
+ {
+ *q++ = *r++; c--;
+ *q++ = *r++; c--;
+ do {
+ *q++ = *r++;
+ } while (--c);
+ }
+ break;
+ }
+ else if ((e & 64) == 0)
+ {
+ t += t->base;
+ e = (t += ((uInt)b & inflate_mask[e]))->exop;
+ }
+ else
+ {
+ z->msg = (char*)"invalid distance code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ break;
+ }
+ if ((e & 64) == 0)
+ {
+ t += t->base;
+ if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)
+ {
+ DUMPBITS(t->bits)
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: * literal '%c'\n" :
+ "inflate: * literal 0x%02x\n", t->base));
+ *q++ = (Byte)t->base;
+ m--;
+ break;
+ }
+ }
+ else if (e & 32)
+ {
+ Tracevv((stderr, "inflate: * end of block\n"));
+ UNGRAB
+ UPDATE
+ return Z_STREAM_END;
+ }
+ else
+ {
+ z->msg = (char*)"invalid literal/length code";
+ UNGRAB
+ UPDATE
+ return Z_DATA_ERROR;
+ }
+ } while (1);
+ } while (m >= 258 && n >= 10);
+
+ /* not enough input or output--restore pointers and return */
+ UNGRAB
+ UPDATE
+ return Z_OK;
+}
diff --git a/lib/zlib/src/inflate.c b/lib/zlib/src/inflate.c index dfb2e86..5577e02 100644 --- a/lib/zlib/src/inflate.c +++ b/lib/zlib/src/inflate.c @@ -1,366 +1,366 @@ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "infblock.h" - -struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ - -typedef enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - DICT4, /* four dictionary check bytes to go */ - DICT3, /* three dictionary check bytes to go */ - DICT2, /* two dictionary check bytes to go */ - DICT1, /* one dictionary check byte to go */ - DICT0, /* waiting for inflateSetDictionary */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ -inflate_mode; - -/* inflate private state */ -struct internal_state { - - /* mode */ - inflate_mode mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int ZEXPORT inflateReset(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, Z_NULL); - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int ZEXPORT inflateEnd(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z); - ZFREE(z, z->state); - z->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - - -int ZEXPORT inflateInit2_(z, w, version, stream_size) -z_streamp z; -int w; -const char *version; -int stream_size; -{ - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream)) - return Z_VERSION_ERROR; - - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; - z->msg = Z_NULL; - if (z->zalloc == Z_NULL) - { - z->zalloc = zcalloc; - z->opaque = (voidpf)0; - } - if (z->zfree == Z_NULL) z->zfree = zcfree; - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Tracev((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int ZEXPORT inflateInit_(z, version, stream_size) -z_streamp z; -const char *version; -int stream_size; -{ - return inflateInit2_(z, DEF_WBITS, version, stream_size); -} - - -#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int ZEXPORT inflate(z, f) -z_streamp z; -int f; -{ - int r; - uInt b; - - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) - { - z->state->mode = BAD; - z->msg = (char*)"unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = (char*)"invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - b = NEXTBYTE; - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev((stderr, "inflate: zlib header ok\n")); - if (!(b & PRESET_DICT)) - { - z->state->mode = BLOCKS; - break; - } - z->state->mode = DICT4; - case DICT4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = DICT3; - case DICT3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = DICT2; - case DICT2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = DICT1; - case DICT1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - z->adler = z->state->sub.check.need; - z->state->mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z->state->mode = BAD; - z->msg = (char*)"need dictionary"; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_STREAM_ERROR; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r == Z_OK) - r = f; - if (r != Z_STREAM_END) - return r; - r = f; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = (char*)"incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Tracev((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } -#ifdef NEED_DUMMY_RETURN - return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ -#endif -} - - -int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) -z_streamp z; -const Bytef *dictionary; -uInt dictLength; -{ - uInt length = dictLength; - - if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) - return Z_STREAM_ERROR; - - if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; - z->adler = 1L; - - if (length >= ((uInt)1<<z->state->wbits)) - { - length = (1<<z->state->wbits)-1; - dictionary += dictLength - length; - } - inflate_set_dictionary(z->state->blocks, dictionary, length); - z->state->mode = BLOCKS; - return Z_OK; -} - - -int ZEXPORT inflateSync(z) -z_streamp z; -{ - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - static const Byte mark[4] = {0, 0, 0xff, 0xff}; - if (*p == mark[m]) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - 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(z) -z_streamp z; -{ - if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) - return Z_STREAM_ERROR; - return inflate_blocks_sync_point(z->state->blocks); -} +/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+
+typedef enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ DICT4, /* four dictionary check bytes to go */
+ DICT3, /* three dictionary check bytes to go */
+ DICT2, /* two dictionary check bytes to go */
+ DICT1, /* one dictionary check byte to go */
+ DICT0, /* waiting for inflateSetDictionary */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ inflate_mode mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z);
+ ZFREE(z, z->state);
+ z->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream))
+ return Z_VERSION_ERROR;
+
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->msg = Z_NULL;
+ if (z->zalloc == Z_NULL)
+ {
+ z->zalloc = zcalloc;
+ z->opaque = (voidpf)0;
+ }
+ if (z->zfree == Z_NULL) z->zfree = zcfree;
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Tracev((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ b = NEXTBYTE;
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ if (!(b & PRESET_DICT))
+ {
+ z->state->mode = BLOCKS;
+ break;
+ }
+ z->state->mode = DICT4;
+ case DICT4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = DICT3;
+ case DICT3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = DICT2;
+ case DICT2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = DICT1;
+ case DICT1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+ z->adler = z->state->sub.check.need;
+ z->state->mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z->state->mode = BAD;
+ z->msg = (char*)"need dictionary";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r == Z_OK)
+ r = f;
+ if (r != Z_STREAM_END)
+ return r;
+ r = f;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+int ZEXPORT inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ uInt length = dictLength;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+ z->adler = 1L;
+
+ if (length >= ((uInt)1<<z->state->wbits))
+ {
+ length = (1<<z->state->wbits)-1;
+ dictionary += dictLength - length;
+ }
+ inflate_set_dictionary(z->state->blocks, dictionary, length);
+ z->state->mode = BLOCKS;
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateSync(z)
+z_streamp z;
+{
+ uInt n; /* number of bytes to look at */
+ Bytef *p; /* pointer to bytes */
+ uInt m; /* number of marker bytes found in a row */
+ uLong r, w; /* temporaries to save total_in and total_out */
+
+ /* set up */
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->mode != BAD)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0;
+ }
+ if ((n = z->avail_in) == 0)
+ return Z_BUF_ERROR;
+ p = z->next_in;
+ m = z->state->sub.marker;
+
+ /* search */
+ while (n && m < 4)
+ {
+ static const Byte mark[4] = {0, 0, 0xff, 0xff};
+ if (*p == mark[m])
+ m++;
+ else if (*p)
+ m = 0;
+ else
+ m = 4 - m;
+ p++, n--;
+ }
+
+ /* restore */
+ z->total_in += p - z->next_in;
+ z->next_in = p;
+ z->avail_in = n;
+ z->state->sub.marker = m;
+
+ /* return no joy or set up to restart on a new block */
+ if (m != 4)
+ return Z_DATA_ERROR;
+ r = z->total_in; w = z->total_out;
+ inflateReset(z);
+ z->total_in = r; z->total_out = w;
+ z->state->mode = BLOCKS;
+ 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(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
+ return Z_STREAM_ERROR;
+ return inflate_blocks_sync_point(z->state->blocks);
+}
diff --git a/lib/zlib/src/inftrees.c b/lib/zlib/src/inftrees.c index 4c32ca3..f89e801 100644 --- a/lib/zlib/src/inftrees.c +++ b/lib/zlib/src/inftrees.c @@ -1,454 +1,454 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#if !defined(BUILDFIXED) && !defined(STDC) -# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ -#endif - -const char inflate_copyright[] = - " inflate 1.1.4 Copyright 1995-2002 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. - */ -struct internal_state {int dummy;}; /* for buggy compilers */ - -/* simplify the use of the inflate_huft type with some defines */ -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - const uIntf *, /* list of base values for non-simple codes */ - const uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - inflate_huft *, /* space for trees */ - uInt *, /* hufts used in space */ - uIntf * )); /* space for values */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ - 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}; - /* see note #13 above about 258 */ -local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ - 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, 112, 112}; /* 112==invalid */ -local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ - 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}; -local const uInt cpdext[30] = { /* Extra bits for distance codes */ - 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}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ - -local int huft_build(b, n, s, d, e, t, m, hp, hn, v) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= 288) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -const uIntf *d; /* list of base values for non-simple codes */ -const uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -inflate_huft *hp; /* space for trees */ -uInt *hn; /* hufts used in space */ -uIntf *v; /* working area: values in order of bit length */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), or Z_DATA_ERROR if the input is invalid. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - n = x[g]; /* set n to length of v */ - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = g - w; - z = z > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate new table */ - if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_DATA_ERROR; /* overflow of MANY */ - u[h] = q = hp + *hn; - *hn += z; - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - j = i >> (w - l); - r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ - u[h-1][j] = r; /* connect to last table */ - } - else - *t = q; /* first table is returned result */ - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - mask = (1 << w) - 1; /* needed on HP, cc -O bug */ - while ((i & mask) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - mask = (1 << w) - 1; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -int inflate_trees_bits(c, bb, tb, hp, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ - - if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, - tb, bb, hp, &hn, v); - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR || *bb == 0) - { - z->msg = (char*)"incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -} - - -int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ -{ - int r; - uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ - - /* allocate work area */ - if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - - /* build literal/length tree */ - r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); - if (r != Z_OK || *bl == 0) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed literal/length tree"; - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; - } - - /* build distance tree */ - r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); - if (r != Z_OK || (*bd == 0 && nl > 257)) - { - if (r == Z_DATA_ERROR) - z->msg = (char*)"oversubscribed distance tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - z->msg = (char*)"incomplete distance tree"; - r = Z_DATA_ERROR; - } - else if (r != Z_MEM_ERROR) - { - z->msg = (char*)"empty distance tree with lengths"; - r = Z_DATA_ERROR; - } - ZFREE(z, v); - return r; -#endif - } - - /* done */ - ZFREE(z, v); - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -#ifdef BUILDFIXED -local int fixed_built = 0; -#define FIXEDH 544 /* number of hufts used by fixed tables */ -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; -#else -#include "inffixed.h" -#endif - - -int inflate_trees_fixed(bl, bd, tl, td, z) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_streamp z; /* for memory allocation */ -{ -#ifdef BUILDFIXED - /* build fixed tables if not already */ - if (!fixed_built) - { - int k; /* temporary variable */ - uInt f = 0; /* number of hufts used in fixed_mem */ - uIntf *c; /* length list for huft_build */ - uIntf *v; /* work area for huft_build */ - - /* allocate memory */ - if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - return Z_MEM_ERROR; - if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) - { - ZFREE(z, c); - return Z_MEM_ERROR; - } - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 9; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, - fixed_mem, &f, v); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, - fixed_mem, &f, v); - - /* done */ - ZFREE(z, v); - ZFREE(z, c); - fixed_built = 1; - } -#endif - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} +/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+const char inflate_copyright[] =
+ " inflate 1.1.4 Copyright 1995-2002 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.
+ */
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ const uIntf *, /* list of base values for non-simple codes */
+ const uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ inflate_huft *, /* space for trees */
+ uInt *, /* hufts used in space */
+ uIntf * )); /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+ 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};
+ /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+ 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, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+ 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};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+ 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};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= 288) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+const uIntf *d; /* list of base values for non-simple codes */
+const uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+inflate_huft *hp; /* space for trees */
+uInt *hn; /* hufts used in space */
+uIntf *v; /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), or Z_DATA_ERROR if the input is invalid. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+ n = x[g]; /* set n to length of v */
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = g - w;
+ z = z > (uInt)l ? l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate new table */
+ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
+ return Z_DATA_ERROR; /* overflow of MANY */
+ u[h] = q = hp + *hn;
+ *hn += z;
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ j = i >> (w - l);
+ r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ else
+ *t = q; /* first table is returned result */
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ mask = (1 << w) - 1; /* needed on HP, cc -O bug */
+ while ((i & mask) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+ tb, bb, hp, &hn, v);
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR || *bb == 0)
+ {
+ z->msg = (char*)"incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate work area */
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+
+ /* build literal/length tree */
+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+ if (r != Z_OK || *bl == 0)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+ }
+
+ /* build distance tree */
+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+ if (r != Z_OK || (*bd == 0 && nl > 257))
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed distance tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ z->msg = (char*)"incomplete distance tree";
+ r = Z_DATA_ERROR;
+ }
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"empty distance tree with lengths";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+#endif
+ }
+
+ /* done */
+ ZFREE(z, v);
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544 /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z; /* for memory allocation */
+{
+#ifdef BUILDFIXED
+ /* build fixed tables if not already */
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ uInt f = 0; /* number of hufts used in fixed_mem */
+ uIntf *c; /* length list for huft_build */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate memory */
+ if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ {
+ ZFREE(z, c);
+ return Z_MEM_ERROR;
+ }
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 9;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+ fixed_mem, &f, v);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+ fixed_mem, &f, v);
+
+ /* done */
+ ZFREE(z, v);
+ ZFREE(z, c);
+ fixed_built = 1;
+ }
+#endif
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
diff --git a/lib/zlib/src/infutil.c b/lib/zlib/src/infutil.c index 9a07622..976d5e5 100644 --- a/lib/zlib/src/infutil.c +++ b/lib/zlib/src/infutil.c @@ -1,87 +1,87 @@ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-2002 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "infblock.h" -#include "inftrees.h" -#include "infcodes.h" -#include "infutil.h" - -struct inflate_codes_state {int dummy;}; /* for buggy compilers */ - -/* And'ing with mask[n] masks the lower n bits */ -uInt inflate_mask[17] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - - -/* copy as much as possible from the sliding window to the output area */ -int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; -{ - uInt n; - Bytef *p; - Bytef *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} +/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt n;
+ Bytef *p;
+ Bytef *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
diff --git a/lib/zlib/src/trees.c b/lib/zlib/src/trees.c index df2ceb2..df3c065 100644 --- a/lib/zlib/src/trees.c +++ b/lib/zlib/src/trees.c @@ -1,1214 +1,1214 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2002 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: trees.c,v 1.1 2003-09-14 18:16:26 pixel Exp $ */ - -/* #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 */ - - -#define MAX(a,b) (a >= b ? a : b) -/* 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 (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) (MAX(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 ascii or binary */ - if (s->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 first the block length 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 (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(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 ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -local void set_data_type(s) - deflate_state *s; -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); -} - -/* =========================================================================== - * 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++); - } -} +/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2002 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: trees.c,v 1.2 2004-11-27 21:35:22 pixel Exp $ */
+
+/* #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 */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* 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 (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) (MAX(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 ascii or binary */
+ if (s->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 first the block length 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 (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(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 ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += s->dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+ s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * 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/lib/zlib/src/uncompr.c b/lib/zlib/src/uncompr.c index ac72129..c7f3ac4 100644 --- a/lib/zlib/src/uncompr.c +++ b/lib/zlib/src/uncompr.c @@ -1,58 +1,58 @@ -/* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: uncompr.c,v 1.1 2003-09-14 18:16:26 pixel Exp $ */ - -#include "zlib.h" - -/* =========================================================================== - 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. -*/ -int ZEXPORT uncompress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - z_stream stream; - int err; - - stream.next_in = (Bytef*)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - 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; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; -} +/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: uncompr.c,v 1.2 2004-11-27 21:35:22 pixel Exp $ */
+
+#include "zlib.h"
+
+/* ===========================================================================
+ 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.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ 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;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/lib/zlib/src/zutil.c b/lib/zlib/src/zutil.c index 6c0f6f6..1e4753e 100644 --- a/lib/zlib/src/zutil.c +++ b/lib/zlib/src/zutil.c @@ -1,225 +1,225 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2002 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id: zutil.c,v 1.1 2003-09-14 18:16:26 pixel Exp $ */ - -#include "zutil.h" - -struct internal_state {int dummy;}; /* for buggy compilers */ - -#ifndef STDC -extern void exit OF((int)); -#endif - -const char *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; -} - -#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); -} - - -#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 __TURBOC__ -#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) -/* Small and medium model in Turbo C are for now limited to near allocation - * with reduced MAX_WBITS and MAX_MEM_LEVEL - */ -# 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 -#endif /* __TURBOC__ */ - - -#if defined(M_I86) && !defined(__32BIT__) -/* 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 /* MSC */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -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 (voidpf)calloc(items, size); -} - -void zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - free(ptr); - if (opaque) return; /* make compiler happy */ -} - -#endif /* MY_ZCALLOC */ +/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c,v 1.2 2004-11-27 21:35:22 pixel Exp $ */
+
+#include "zutil.h"
+
+struct internal_state {int dummy;}; /* for buggy compilers */
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *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;
+}
+
+#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);
+}
+
+
+#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 __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+# 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
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* 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 /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+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 (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
|