[pure-lang-svn] SF.net SVN: pure-lang:[512] pure/trunk
Status: Beta
Brought to you by:
agraef
|
From: <ag...@us...> - 2008-08-16 21:27:32
|
Revision: 512
http://pure-lang.svn.sourceforge.net/pure-lang/?rev=512&view=rev
Author: agraef
Date: 2008-08-16 21:27:39 +0000 (Sat, 16 Aug 2008)
Log Message:
-----------
Implement new script search algorithm.
Modified Paths:
--------------
pure/trunk/ChangeLog
pure/trunk/interpreter.cc
pure/trunk/interpreter.hh
pure/trunk/lexer.ll
Modified: pure/trunk/ChangeLog
===================================================================
--- pure/trunk/ChangeLog 2008-08-16 00:54:21 UTC (rev 511)
+++ pure/trunk/ChangeLog 2008-08-16 21:27:39 UTC (rev 512)
@@ -1,3 +1,24 @@
+2008-08-16 Albert Graef <Dr....@t-...>
+
+ * interpreter.cc, lexer.ll: Implemented new script search
+ algorithm, as discussed on the mailing list.
+
+ Scripts loaded with a 'using' clause are now first searched in the
+ directory of the script containing the 'using' clause, then in the
+ PURELIB directory and finally in the current directory. This
+ allows scripts to be installed in their own directory, along with
+ any other non-library modules they need. Scripts specified on the
+ command line or with the 'run' command are searched for in the
+ current directory and then in the PURELIB directory, as before.
+
+ Script names are now "canonicalized" by following symbolic links
+ (albeit only one level) and removing '.' and '..' directory
+ components in the absolute pathname. Also, checking whether a
+ script has already been loaded now uses the canonicalized pathname
+ so that, e.g., two scripts foo/baz.pure and bar/baz.pure are
+ considered distinct modules and can both be used in the same
+ program (unless they link to the same script file).
+
2008-08-15 Albert Graef <Dr....@t-...>
* test/test018.pure: Add test for integer marshalling.
Modified: pure/trunk/interpreter.cc
===================================================================
--- pure/trunk/interpreter.cc 2008-08-16 00:54:21 UTC (rev 511)
+++ pure/trunk/interpreter.cc 2008-08-16 21:27:39 UTC (rev 512)
@@ -387,6 +387,124 @@
}
}
+/* Search for a source file. Absolute file names (starting with a slash) are
+ taken as is. Relative pathnames are resolved using the following algorithm:
+ If srcdir is nonempty, search it first, then libdir (if nonempty), then the
+ current working directory. If srcdir is empty, first search the current
+ directory, then libdir (if nonempty). In either case, if the resulting
+ absolute pathname is a symbolic link, the destination is used instead, and
+ finally the pathname is canonicalized. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+static inline string dirname(const string& fname)
+{
+ size_t pos = fname.rfind('/');
+ if (pos == string::npos)
+ return "";
+ else
+ return fname.substr(0, pos+1);
+}
+
+static inline string basename(const string& fname)
+{
+ size_t pos = fname.rfind('/');
+ if (pos == string::npos)
+ return fname;
+ else
+ return fname.substr(pos+1);
+}
+
+static inline bool chkfile(const string& s)
+{
+ struct stat st;
+ return !stat(s.c_str(), &st) && !S_ISDIR(st.st_mode);
+}
+
+#ifndef _WIN32
+static inline bool chklink(const string& s)
+{
+ struct stat st;
+ return !lstat(s.c_str(), &st) && S_ISLNK(st.st_mode);
+}
+#endif
+
+#define BUFSIZE 1024
+
+static string searchdir(const string& srcdir, const string& libdir,
+ const string& script)
+{
+ char cwd[BUFSIZE];
+ if (script.empty())
+ return script;
+ else if (!getcwd(cwd, BUFSIZE)) {
+ perror("getcwd");
+ return script;
+ }
+ string workdir = cwd;
+ if (!workdir.empty() && workdir[workdir.size()-1] != '/')
+ workdir += "/";
+ string fname;
+ if (script[0] != '/') {
+ // resolve relative pathname
+ if (srcdir.empty()) {
+ fname = workdir+script;
+ if (chkfile(fname)) goto found;
+ if (!libdir.empty()) {
+ fname = libdir+script;
+ if (chkfile(fname)) goto found;
+ }
+ fname = script;
+ } else {
+ fname = srcdir+script;
+ if (chkfile(fname)) goto found;
+ if (!libdir.empty()) {
+ fname = libdir+script;
+ if (chkfile(fname)) goto found;
+ }
+ fname = workdir+script;
+ if (chkfile(fname)) goto found;
+ fname = script;
+ }
+ } else
+ fname = script;
+ found:
+ if (fname[0] != '/') fname = workdir+fname;
+ char buf[BUFSIZE];
+#ifndef _WIN32
+ if (chklink(fname)) {
+ // follow symbolic link to its destination
+ int l = readlink(fname.c_str(), buf, BUFSIZE-1);
+ if (l >= 0) {
+ buf[l] = 0;
+ string basedir = dirname(fname), linkname = buf;
+ string dir = dirname(linkname), name = basename(linkname);
+ if (dir.empty())
+ dir = basedir;
+ else if (dir[0] != '/')
+ dir = basedir+dir;
+ fname = dir+name;
+ } else
+ perror("readlink");
+ }
+#endif
+ // canonicalize the pathname
+ string dir = dirname(fname), name = basename(fname);
+ if (chdir(dir.c_str())==0 && getcwd(buf, BUFSIZE)) {
+ string dir = buf;
+ if (!dir.empty() && dir[dir.size()-1] != '/')
+ dir += "/";
+ fname = dir+name;
+ }
+ chdir(cwd);
+#if DEBUG>1
+ std::cerr << "search '" << script << "', found as '" << fname << "'\n";
+#endif
+ return fname;
+}
+
// Run the interpreter on a source file, collection of source files, or on
// string data.
@@ -415,7 +533,8 @@
return 0;
}
// ordinary source file
- if (check && sources.find(s) != sources.end())
+ string fname = searchdir(srcdir, lib, s);
+ if (check && sources.find(fname) != sources.end())
// already loaded, skip
return 0;
// save local data
@@ -424,6 +543,7 @@
int l_nerrs = nerrs;
uint8_t l_temp = temp;
const char *l_source_s = source_s;
+ string l_srcdir = srcdir;
// save global data
uint8_t s_verbose = g_verbose;
bool s_interactive = g_interactive;
@@ -435,11 +555,12 @@
nerrs = 0;
source = s; declare_op = false;
source_s = 0;
+ srcdir = dirname(fname);
errmsg.clear();
if (check && !interactive) temp = 0;
- bool ok = lex_begin();
+ bool ok = lex_begin(fname);
if (ok) {
- if (temp == 0 && !s.empty()) sources.insert(s);
+ if (temp == 0 && !s.empty()) sources.insert(fname);
yy::parser parser(*this);
parser.set_debug_level((verbose&verbosity::parser) != 0);
// parse
@@ -460,6 +581,7 @@
nerrs = l_nerrs;
temp = l_temp;
source_s = l_source_s;
+ srcdir = l_srcdir;
// return last computed result, if any
return result;
}
@@ -488,6 +610,7 @@
string l_source = source;
int l_nerrs = nerrs;
const char *l_source_s = source_s;
+ string l_srcdir = srcdir;
// save global data
uint8_t s_verbose = g_verbose;
bool s_interactive = g_interactive;
@@ -499,6 +622,7 @@
nerrs = 0;
source = ""; declare_op = false;
source_s = s.c_str();
+ srcdir = "";
errmsg.clear();
bool ok = lex_begin();
if (ok) {
@@ -519,6 +643,7 @@
source_s = 0;
nerrs = l_nerrs;
source_s = l_source_s;
+ srcdir = l_srcdir;
// return last computed result, if any
return result;
}
Modified: pure/trunk/interpreter.hh
===================================================================
--- pure/trunk/interpreter.hh 2008-08-16 00:54:21 UTC (rev 511)
+++ pure/trunk/interpreter.hh 2008-08-16 21:27:39 UTC (rev 512)
@@ -618,8 +618,9 @@
// Interface to the lexer.
public:
bool declare_op;
+ string srcdir;
private:
- bool lex_begin();
+ bool lex_begin(const string& fname = "");
void lex_end();
};
Modified: pure/trunk/lexer.ll
===================================================================
--- pure/trunk/lexer.ll 2008-08-16 00:54:21 UTC (rev 511)
+++ pure/trunk/lexer.ll 2008-08-16 21:27:39 UTC (rev 512)
@@ -852,19 +852,14 @@
%%
bool
-interpreter::lex_begin()
+interpreter::lex_begin(const string& fname)
{
yy_flex_debug = (verbose&verbosity::lexer) != 0 && !source_s;
if (source_s)
yyin = 0;
else if (source.empty())
yyin = stdin;
- else if (!(yyin = fopen(source.c_str(), "r")) && source[0] != '/') {
- string fname = lib+source;
- if (!(yyin = fopen(fname.c_str(), "r")))
- perror(source.c_str());
- //error("cannot open '" + source + "'");
- } else if (!yyin)
+ else if (!(yyin = fopen(fname.c_str(), "r")))
//error("cannot open '" + source + "'");
perror(source.c_str());
if (source_s || yyin) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|