applied windows patch from #3274

This commit is contained in:
Brian Gerkey 2011-01-30 00:12:22 +00:00
parent 3624d67266
commit d353445182
6 changed files with 533 additions and 67 deletions

View File

@ -132,6 +132,18 @@ file called @b manifest.xml.
*/
#if defined(WIN32)
#if defined(ROS_STATIC)
#define ROSPACK_EXPORT
#elif defined(rospack_EXPORTS)
#define ROSPACK_EXPORT __declspec(dllexport)
#else
#define ROSPACK_EXPORT __declspec(dllimport)
#endif
#else
#define ROSPACK_EXPORT
#endif
#include <string>
#include <vector>
#include <list>
@ -155,11 +167,16 @@ typedef std::list<Acc> AccList;
/**
* The Package class contains information about a single package
*/
class Package
class ROSPACK_EXPORT Package
{
public:
enum traversal_order_t { POSTORDER, PREORDER };
std::string name, path;
// These will cause warnings on Windows when compiling the DLL because they
// are static. They should more correctly be accessed via accessor functions
// that are exported from the class, rather than directly, in order to
// "prevent data corruption." Since main.cpp is currently the only known
// client and it doesn't use them, I'm not caring about the warnings yet.
static std::vector<Package *> pkgs;
static std::vector<Package *> deleted_pkgs;
@ -205,7 +222,7 @@ private:
* The ROSPack class contains information the entire package dependency
* tree.
*/
class ROSPack
class ROSPACK_EXPORT ROSPack
{
public:
static const char* usage();

View File

@ -40,6 +40,18 @@
a single binary, called \b %rosstack.
*/
#if defined(WIN32)
#if defined(ROS_STATIC)
#define ROSSTACK_EXPORT
#elif defined(rosstack_EXPORTS)
#define ROSSTACK_EXPORT __declspec(dllexport)
#else
#define ROSSTACK_EXPORT __declspec(dllimport)
#endif
#else
#define ROSSTACK_EXPORT
#endif
#include <string>
#include <vector>
@ -49,18 +61,19 @@ a single binary, called \b %rosstack.
namespace rosstack
{
class Stack;
class ROSSTACK_EXPORT Stack;
// global helper functions
void string_split(const std::string &s, std::vector<std::string> &t, const std::string &d);
bool file_exists(const std::string &fname);
extern const char *fs_delim;
extern const char *path_delim;
Stack *g_get_stack(const std::string &name);
typedef std::vector<Stack *> VecStack;
/**
* The Stack class contains information about a single stack
*/
class Stack
class ROSSTACK_EXPORT Stack
{
public:
enum traversal_order_t { POSTORDER, PREORDER };
@ -95,7 +108,7 @@ private:
* The ROSStack class contains information the entire stack dependency
* tree.
*/
class ROSStack
class ROSSTACK_EXPORT ROSStack
{
public:
static const char* usage();

View File

@ -31,7 +31,9 @@
#include "rospack/rospack.h"
#include <stdexcept>
#include <unistd.h>
#if !defined(WIN32)
#include <unistd.h>
#endif
#include <stdlib.h>
int main(int argc, char **argv)
@ -42,6 +44,7 @@ int main(int argc, char **argv)
return 0;
}
#if !defined(WIN32)
// If it looks we're running under sudo, try to drop back to the normal
// user, to avoid writing the cache with inappropriate permissions,
// #2884.
@ -60,6 +63,7 @@ int main(int argc, char **argv)
if(setuid(sudo_uid))
perror("[rospack] Failed to change UID; cache permissions may need to be adjusted manually. setuid()");
}
#endif
int ret;
bool quiet;

View File

@ -37,16 +37,38 @@
#include <stack>
#include <queue>
#include <cassert>
#include <unistd.h>
#include <dirent.h>
#if !defined(WIN32)
#include <unistd.h>
#include <dirent.h>
#include <sys/time.h>
#include <sys/file.h>
#endif
#include <stdexcept>
#include <sys/time.h>
#include <sys/file.h>
#include <time.h>
#include <sstream>
#include <iterator>
#include <libgen.h>
#if !defined(WIN32)
#include <libgen.h>
#endif
#if defined(WIN32)
#include <direct.h>
#include <Winsock2.h> // For struct timeval (that's awful)
#include <time.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#define PATH_MAX MAX_PATH
#define snprintf _snprintf
#define popen _popen
#define pclose _pclose
#define getcwd _getcwd
#define mkdir(a,b) _mkdir(a)
#define fdopen _fdopen
#define access _access
#define F_OK 0x00
#endif
#include "tinyxml-2.5.3/tinyxml.h"
#include "rospack/rospack.h"
@ -60,7 +82,11 @@ const int MAX_DIRECTORY_DEPTH = 1000; // used to detect self-referencing symlink
#include <sys/stat.h>
#ifndef S_ISDIR
#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
#if defined(WIN32)
#define S_ISDIR(x) (((x) & FILE_ATTRIBUTE_DIRECTORY) != 0)
#else
#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
#endif
#endif
namespace rospack
@ -69,12 +95,41 @@ namespace rospack
ROSPack *g_rospack = NULL; // singleton
#ifdef __APPLE__
const string g_ros_os("osx");
const string g_ros_os("osx");
#else
const string g_ros_os("linux");
#if defined(WIN32)
const string g_ros_os("win32");
#else
const string g_ros_os("linux");
#endif
#endif
const char *fs_delim = "/"; // ifdef this for windows
#if defined(WIN32)
// This isn't entirely necessary - the Win32 API functions handle / just as
// well as \ for paths, and CMake chokes if we output paths with \ in them
// anyway.
const char *fs_delim = "\\";
const char *path_delim = ";";
#else
const char *fs_delim = "/";
const char *path_delim = ":";
#endif
inline string ToUnixPathDelim(string path)
{
#if defined(WIN32)
// CMake chokes on Windows-style path separators (it thinks they're
// escapes), so either they must be escaped or replaced with UNIX-style
// separators. (If there are any real escapes in s, this will go boom.)
string token("\\");
for (string::size_type ii = path.find(token); ii != string::npos;
ii = path.find(token, ii))
{
path.replace(ii, token.length(), string("/"));
}
#endif
return path;
}
Package::Package(string _path) : path(_path),
deps_calculated(false), direct_deps_calculated(false),
@ -337,7 +392,7 @@ const vector<Package *> &Package::direct_deps(bool missing_package_as_warning)
if (direct_deps_calculated)
return _direct_deps;
#ifdef VERBOSE_DEBUG
printf("calculating direct deps for package [%s]\n", name.c_str());
fprintf(stderr, "calculating direct deps for package [%s]\n", name.c_str());
#endif
TiXmlElement *mroot = manifest_root();
TiXmlNode *dep_node = 0;
@ -356,7 +411,7 @@ const vector<Package *> &Package::direct_deps(bool missing_package_as_warning)
// cause a recrawl, which blows aways the accumulated data structure.
char* dep_pkgname_copy = strdup(dep_pkgname);
#ifdef VERBOSE_DEBUG
printf("direct_deps: pkg %s has dep %s\n", name.c_str(), dep_pkgname_copy);
fprintf(stderr, "direct_deps: pkg %s has dep %s\n", name.c_str(), dep_pkgname_copy);
#endif
try
{
@ -833,7 +888,7 @@ int ROSPack::cmd_find()
// todo: obey the search order
Package *p = get_pkg(opt_package);
//printf("%s\n", p->path.c_str());
output_acc += p->path + "\n";
output_acc += ToUnixPathDelim(p->path) + "\n";
return 0;
}
@ -843,7 +898,7 @@ int ROSPack::cmd_deps()
for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
{
//printf("%s\n", (*i)->name.c_str());
output_acc += (*i)->name + "\n";
output_acc += ToUnixPathDelim((*i)->name) + "\n";
}
return 0;
}
@ -854,7 +909,7 @@ int ROSPack::cmd_deps_manifests()
for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
{
//printf("%s/manifest.xml ", (*i)->path.c_str());
output_acc += (*i)->path + "/manifest.xml ";
output_acc += ToUnixPathDelim((*i)->path + "/manifest.xml ");
}
//puts("");
output_acc += "\n";
@ -867,17 +922,17 @@ int ROSPack::cmd_deps_msgsrv()
for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
{
Package* p = *i;
bool msg_exists = file_exists((p->path + "/msg_gen/generated").c_str());
bool srv_exists = file_exists((p->path + "/srv_gen/generated").c_str());
bool msg_exists = file_exists(ToUnixPathDelim(p->path + "/msg_gen/generated").c_str());
bool srv_exists = file_exists(ToUnixPathDelim(p->path + "/srv_gen/generated").c_str());
if (msg_exists)
{
output_acc += p->path + "/msg_gen/generated ";
output_acc += ToUnixPathDelim(p->path + "/msg_gen/generated ");
}
if (srv_exists)
{
output_acc += p->path + "/srv_gen/generated ";
output_acc += ToUnixPathDelim(p->path + "/srv_gen/generated ");
}
}
output_acc += "\n";
@ -890,7 +945,7 @@ int ROSPack::cmd_deps1()
for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
{
//printf("%s\n", (*i)->name.c_str());
output_acc += (*i)->name + "\n";
output_acc += ToUnixPathDelim((*i)->name) + "\n";
}
return 0;
}
@ -907,7 +962,7 @@ int ROSPack::cmd_depsindent(Package* pkg, int indent)
output_acc += " ";
}
//printf("%s\n", (*i)->name.c_str());
output_acc += (*i)->name + "\n";
output_acc += ToUnixPathDelim((*i)->name) + "\n";
cmd_depsindent(*i, indent+2);
}
return 0;
@ -1004,7 +1059,7 @@ int ROSPack::cmd_libs_only(string token)
lflags = deduplicate_tokens(lflags);
}
//printf("%s\n", lflags.c_str());
output_acc += lflags + "\n";
output_acc += ToUnixPathDelim(lflags) + "\n";
return 0;
}
@ -1019,7 +1074,7 @@ int ROSPack::cmd_cflags_only(string token)
cflags = deduplicate_tokens(cflags);
}
//printf("%s\n", cflags.c_str());
output_acc += cflags + "\n";
output_acc += ToUnixPathDelim(cflags) + "\n";
return 0;
}
@ -1027,7 +1082,7 @@ void ROSPack::export_flags(string pkg, string lang, string attrib)
{
string flags = get_pkg(pkg)->flags(lang, attrib);
//printf("%s\n", flags.c_str());
output_acc += flags + "\n";
output_acc += ToUnixPathDelim(flags) + "\n";
}
int ROSPack::cmd_versioncontrol(int depth)
@ -1285,7 +1340,24 @@ int ROSPack::run(int argc, char **argv)
if(getcwd(buf,sizeof(buf)))
{
if(Package::is_package("."))
{
#if defined(WIN32)
// No basename on Windows; use _splitpath_s instead
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
_splitpath_s(buf, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
ext, _MAX_EXT);
char filename[_MAX_FNAME + _MAX_EXT];
if (ext[0] != '\0')
{
_makepath_s(filename, _MAX_FNAME + _MAX_EXT, NULL, NULL, fname, ext);
opt_package = string(filename);
}
else
opt_package = string(fname);
#else
opt_package = string(basename(buf));
#endif
}
}
}
@ -1304,7 +1376,7 @@ int ROSPack::run(int argc, char **argv)
opt_profile_length = 20; // default is about a screenful or so
}
#ifdef VERBOSE_DEBUG
printf("profile_length = %d\n", opt_profile_length);
fprintf(stderr, "profile_length = %d\n", opt_profile_length);
#endif
// re-crawl with profiling enabled
crawl_for_packages(true);
@ -1455,7 +1527,11 @@ string ROSPack::getCachePath()
//
// By providing the trailing slash, stat() will only succeed if the
// path exists AND is a directory.
#if defined(WIN32)
std::string ros_home_slash = ros_home + std::string("\\");
#else
std::string ros_home_slash = ros_home + std::string("/");
#endif
struct stat s;
if(stat(ros_home_slash.c_str(), &s))
{
@ -1468,6 +1544,7 @@ string ROSPack::getCachePath()
}
else
{
// UNIXONLY
// Not cross-platform?
ros_home = getenv("HOME");
if (ros_home)
@ -1502,7 +1579,7 @@ bool ROSPack::cache_is_good()
{
double dt = difftime(time(NULL), s.st_mtime);
#ifdef VERBOSE_DEBUG
printf("cache age: %f\n", dt);
fprintf(stderr, "cache age: %f\n", dt);
#endif
// Negative cache_max_age means it's always new enough. It's dangerous
// for the user to set this, but rosbash uses it.
@ -1566,9 +1643,27 @@ public:
double ROSPack::time_since_epoch()
{
#if defined(WIN32)
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
#endif
FILETIME ft;
unsigned __int64 tmpres = 0;
GetSystemTimeAsFileTime(&ft);
tmpres |= ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
tmpres /= 10;
tmpres -= DELTA_EPOCH_IN_MICROSECS;
return static_cast<double>(tmpres) / 1e6;
#else
struct timeval tod;
gettimeofday(&tod, NULL);
return tod.tv_sec + 1e-6 * tod.tv_usec;
#endif
}
// Add package, filtering out duplicates.
@ -1617,7 +1712,7 @@ void ROSPack::crawl_for_packages(bool force_crawl)
if (cache) // one last check just in case nutty stuff happened in between
{
#ifdef VERBOSE_DEBUG
printf("trying to use cache...\n");
fprintf(stderr, "trying to use cache...\n");
#endif
char linebuf[30000];
for(;;)
@ -1639,14 +1734,14 @@ void ROSPack::crawl_for_packages(bool force_crawl)
// if we get here, this means the cache either bogus or we've been
// instructed to rebuild it.
#ifdef VERBOSE_DEBUG
printf("building cache\n");
fprintf(stderr, "building cache\n");
#endif
deque<CrawlQueueEntry> q;
q.push_back(CrawlQueueEntry(ros_root));
if (char *rpp = getenv("ROS_PACKAGE_PATH"))
{
vector<string> rppvec;
string_split(rpp, rppvec, ":");
string_split(rpp, rppvec, path_delim);
sanitize_rppvec(rppvec);
for (vector<string>::iterator i = rppvec.begin(); i != rppvec.end(); ++i)
{
@ -1716,6 +1811,62 @@ void ROSPack::crawl_for_packages(bool force_crawl)
cqe.start_num_pkgs = total_num_pkgs;
q.push_front(cqe);
}
#if defined(WIN32)
WIN32_FIND_DATA find_file_data;
HANDLE hfind = INVALID_HANDLE_VALUE;
if ((hfind = FindFirstFile((cqe.path + "\\*").c_str(),
&find_file_data)) == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "[rospack] FindFirstFile error %u while crawling %s\n",
GetLastError(), cqe.path.c_str());
continue;
}
do
{
if (!S_ISDIR(find_file_data.dwFileAttributes))
continue; // Ignore non-directories
if (find_file_data.cFileName[0] == '.')
continue; // Ignore hidden directories
string child_path = cqe.path + fs_delim + string(find_file_data.cFileName);
if (Package::is_package(child_path))
{
total_num_pkgs++;
// Filter out duplicates; first encountered takes precedence
Package* newp = new Package(child_path);
// TODO: make this check more efficient
bool dup = false;
for(std::vector<Package *>::const_iterator it = Package::pkgs.begin();
it != Package::pkgs.end();
it++)
{
if((*it)->name == newp->name)
{
dup=true;
break;
}
}
if(dup)
delete newp;
else
{
Package::pkgs.push_back(newp);
}
}
//check to make sure we're allowed to descend
else if (!Package::is_no_subdirs(child_path))
q.push_front(CrawlQueueEntry(child_path));
}
while (FindNextFile(hfind, &find_file_data) != 0);
DWORD last_error = GetLastError();
FindClose(hfind);
if (last_error != ERROR_NO_MORE_FILES)
{
fprintf(stderr, "[rospack] FindNextFile error %u while crawling %s\n",
GetLastError(), cqe.path.c_str());
continue;
}
#else
DIR *d = opendir(cqe.path.c_str());
if (!d)
{
@ -1747,6 +1898,7 @@ void ROSPack::crawl_for_packages(bool force_crawl)
q.push_front(CrawlQueueEntry(child_path));
}
closedir(d);
#endif
}
crawled = true; // don't try to re-crawl if we can't find something
const double crawl_elapsed_time = time_since_epoch() - crawl_start_time;
@ -1762,7 +1914,31 @@ void ROSPack::crawl_for_packages(bool force_crawl)
char tmp_cache_dir[PATH_MAX];
char tmp_cache_path[PATH_MAX];
strncpy(tmp_cache_dir, cache_path.c_str(), sizeof(tmp_cache_dir));
#if defined(WIN32)
// No dirname on Windows; use _splitpath_s instead
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
_splitpath_s(tmp_cache_dir, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
ext, _MAX_EXT);
char full_dir[_MAX_DRIVE + _MAX_DIR];
_makepath_s(full_dir, _MAX_DRIVE + _MAX_DIR, drive, dir, NULL, NULL);
snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s\\.rospack_cache.XXXXXX", full_dir);
#else
snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s/.rospack_cache.XXXXXX", dirname(tmp_cache_dir));
#endif
#if defined(WIN32)
// This one is particularly nasty: on Windows, there is no equivalent of
// mkstemp, so we're stuck with the security risks of mktemp. Hopefully not a
// problem in our use cases.
if (_mktemp_s(tmp_cache_path, PATH_MAX) != 0)
{
fprintf(stderr,
"[rospack] Unable to generate temporary cache file name: %u",
GetLastError());
}
else
{
FILE *cache = fopen(tmp_cache_path, "w");
#else
int fd = mkstemp(tmp_cache_path);
if (fd < 0)
{
@ -1772,6 +1948,7 @@ void ROSPack::crawl_for_packages(bool force_crawl)
else
{
FILE *cache = fdopen(fd, "w");
#endif
if (!cache)
{
fprintf(stderr, "[rospack] Unable open cache file %s: %s\n",
@ -1786,6 +1963,8 @@ void ROSPack::crawl_for_packages(bool force_crawl)
pkg != Package::pkgs.end(); ++pkg)
fprintf(cache, "%s\n", (*pkg)->path.c_str());
fclose(cache);
if(file_exists(cache_path.c_str()))
remove(cache_path.c_str());
if(rename(tmp_cache_path, cache_path.c_str()) < 0)
{
fprintf(stderr, "[rospack] Error: failed to rename cache file %s to %s: %s\n",
@ -1894,6 +2073,59 @@ VecPkg ROSPack::partial_crawl(const string &path)
CrawlQueueEntry cqe = q.front();
//printf("crawling %s\n", cqe.path.c_str());
q.pop_front();
#if defined(WIN32)
WIN32_FIND_DATA find_file_data;
HANDLE hfind = INVALID_HANDLE_VALUE;
if ((hfind = FindFirstFile((cqe.path + "\\*").c_str(),
&find_file_data)) == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "[rospack] FindFirstFile error %u while crawling %s\n",
GetLastError(), cqe.path.c_str());
continue;
}
do
{
if (!S_ISDIR(find_file_data.dwFileAttributes))
continue; // Ignore non-directories
if (find_file_data.cFileName[0] == '.')
continue; // Ignore hidden directories
string child_path = cqe.path + fs_delim + string(find_file_data.cFileName);
if (Package::is_package(child_path))
{
// Filter out duplicates; first encountered takes precedence
Package* newp = new Package(child_path);
// TODO: make this check more efficient
bool dup = false;
for(std::vector<Package *>::const_iterator it = partial_pkgs.begin();
it != partial_pkgs.end();
it++)
{
if((*it)->name == newp->name)
{
dup=true;
break;
}
}
if(dup)
delete newp;
else
partial_pkgs.push_back(newp);
}
//check to make sure we're allowed to descend
else if (!Package::is_no_subdirs(child_path))
q.push_front(CrawlQueueEntry(child_path));
}
while (FindNextFile(hfind, &find_file_data) != 0);
DWORD last_error = GetLastError();
FindClose(hfind);
if (last_error != ERROR_NO_MORE_FILES)
{
fprintf(stderr, "[rospack] FindNextFile error %u while crawling %s\n",
GetLastError(), cqe.path.c_str());
continue;
}
#else
DIR *d = opendir(cqe.path.c_str());
if (!d)
{
@ -1941,6 +2173,7 @@ VecPkg ROSPack::partial_crawl(const string &path)
q.push_front(CrawlQueueEntry(child_path));
}
closedir(d);
#endif
}
return partial_pkgs;
}
@ -1999,6 +2232,7 @@ string ROSPack::deduplicate_tokens(const string& s)
bool file_exists(const string &fname)
{
// this will be different in windows
// ^^ For once, it's actually _not_ that different
return (access(fname.c_str(), F_OK) == 0);
}

View File

@ -38,17 +38,38 @@
#include <stack>
#include <queue>
#include <cassert>
#include <unistd.h>
#include <dirent.h>
#if !defined(WIN32)
#include <unistd.h>
#include <dirent.h>
#include <sys/time.h>
#include <sys/file.h>
#include <stdint.h>
#endif
#include <stdexcept>
#include <sys/time.h>
#include <sys/file.h>
#include <time.h>
#include <sstream>
#include <iterator>
#include <stdint.h>
#include <libgen.h>
#if !defined(WIN32)
#include <libgen.h>
#endif
#if defined(WIN32)
#include <direct.h>
#include <time.h>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#define PATH_MAX MAX_PATH
#define snprintf _snprintf
#define getcwd _getcwd
#define fdopen _fdopen
#define access _access
#define F_OK 0x00
#define W_OK 0x02
#define R_OK 0x04
#define mkdir(a,b) _mkdir(a)
#endif
#include "tinyxml-2.5.3/tinyxml.h"
#include "rospack/rosstack.h"
@ -68,9 +89,45 @@ using namespace rosstack;
#ifdef __APPLE__
const string g_ros_os("osx");
#else
const string g_ros_os("linux");
#if defined(WIN32)
const string g_ros_os("win32");
#else
const string g_ros_os("linux");
#endif
#endif
#if defined(WIN32)
// The MS compiler complains bitterly about undefined symbols due to the
// static members of the TiXmlBase class. They need to exist in every
// compilation unit (i.e. DLL or EXE), but they don't get exported
// properly across DLL boundaries (for reasons I've tried to investigate,
// before deciding it was a waste of my time). So they're defined here as well
// to keep rosstack happy (rospack's lib links directly to tinyxml.cpp,
// rosstack's lib does not).
// I'll fix this later. Thanks, MS, for creating yet another broken system.
const int TiXmlBase::utf8ByteTable[256] =
{
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte
4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
};
bool TiXmlBase::condenseWhiteSpace = true;
#endif
//////////////////////////////////////////////////////////////////////////////
// Global storage for --foo options
// --deps-only
@ -80,20 +137,30 @@ string g_length;
// The stack name
string g_stack;
// the number of entries to list in the profile table
uint32_t g_profile_length = 0;
unsigned int g_profile_length = 0;
// global singleton rosstack pointer... yeah, I know.
ROSStack *g_rosstack = NULL;
//////////////////////////////////////////////////////////////////////////////
const char *rosstack::fs_delim = "/"; // ifdef this for windows someday
#if defined(WIN32)
// This isn't entirely necessary - the Win32 API functions handle / just as
// well as \ for paths, and CMake chokes if we output paths with \ in them
// anyway.
const char *rosstack::fs_delim = "\\";
const char *rosstack::path_delim = ";";
#else
const char *rosstack::fs_delim = "/";
const char *rosstack::path_delim = ":";
#endif
Stack::Stack(string _path) : path(_path),
deps_calculated(false), direct_deps_calculated(false),
descendants_calculated(false), manifest_loaded(false)
{
vector<string> path_tokens;
string_split(path, path_tokens, "/");
string_split(path, path_tokens, fs_delim);
name = path_tokens.back();
// Don't load the manifest here, because it causes spurious errors to be
// printed if the stack has been moved (#1785). Presumably the manifest
@ -120,7 +187,7 @@ const VecStack &Stack::deps(traversal_order_t order, int depth)
{
if (depth > 1000)
{
fprintf(stderr,"[rospack] woah! expanding the dependency tree made it blow "
fprintf(stderr,"[rosstack] woah! expanding the dependency tree made it blow "
"up.\n There must be a circular dependency somewhere.\n");
throw runtime_error(string("circular dependency"));
}
@ -503,7 +570,7 @@ string ROSStack::lookup_owner(string pkg_name, bool just_owner_name)
if (rpp)
{
vector<string> rppvec;
string_split(rpp, rppvec, ":");
string_split(rpp, rppvec, path_delim);
sanitize_rppvec(rppvec);
for (vector<string>::iterator i = rppvec.begin(); i != rppvec.end(); ++i)
bases[*i] = string("");
@ -648,7 +715,22 @@ int ROSStack::run(int argc, char **argv)
char buf[1024];
if(!getcwd(buf,sizeof(buf)))
throw runtime_error(errmsg);
#if defined(WIN32)
// No basename on Windows; use _splitpath_s instead
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
_splitpath_s(buf, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
ext, _MAX_EXT);
char filename[_MAX_FNAME + _MAX_EXT];
if (ext[0] != '\0')
{
_makepath_s(filename, _MAX_FNAME + _MAX_EXT, NULL, NULL, fname, ext);
g_stack = string(filename);
}
else
g_stack = string(fname);
#else
g_stack = string(basename(buf));
#endif
}
if (i != argc)
@ -741,13 +823,13 @@ void ROSStack::createROSHomeDirectory()
string ROSStack::getCachePath()
{
string path;
path = string(ros_root) + "/.rosstack_cache";
path = string(ros_root) + fs_delim + ".rosstack_cache";
if (access(ros_root, W_OK) == 0)
return path;
// if we cannot write into the ros_root, then let's try to
// write into the user's .ros directory.
createROSHomeDirectory();
path = string(getenv("HOME")) + "/.ros/rosstack_cache";
path = string(getenv("HOME")) + fs_delim + ".ros" + fs_delim + "rosstack_cache";
return path;
}
@ -837,9 +919,27 @@ public:
double ROSStack::time_since_epoch()
{
#if defined(WIN32)
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
#endif
FILETIME ft;
unsigned __int64 tmpres = 0;
GetSystemTimeAsFileTime(&ft);
tmpres |= ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
tmpres /= 10;
tmpres -= DELTA_EPOCH_IN_MICROSECS;
return static_cast<double>(tmpres) / 1e6;
#else
struct timeval tod;
gettimeofday(&tod, NULL);
return tod.tv_sec + 1e-6 * tod.tv_usec;
#endif
}
// Add stack, filtering out duplicates.
@ -925,7 +1025,7 @@ void ROSStack::crawl_for_stacks(bool force_crawl)
char *rpp = getenv("ROS_PACKAGE_PATH");
if (rpp)
rsp = string(rpp);
string_split(rsp, rspvec, ":");
string_split(rsp, rspvec, path_delim);
sanitize_rppvec(rspvec);
#ifdef VERBOSE_DEBUG
printf("seeding crawler with [%s], which has %lu entries\n", rsp.c_str(), rspvec.size());
@ -975,6 +1075,64 @@ void ROSStack::crawl_for_stacks(bool force_crawl)
cqe.start_time = time_since_epoch();
q.push_front(cqe);
}
#if defined(WIN32)
// And again...
WIN32_FIND_DATA find_file_data;
HANDLE hfind = INVALID_HANDLE_VALUE;
if ((hfind = FindFirstFile((cqe.path + "\\*").c_str(),
&find_file_data)) == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "[rosstack] FindFirstFile error %u while crawling %s\n",
GetLastError(), cqe.path.c_str());
continue;
}
do
{
if (!S_ISDIR(find_file_data.dwFileAttributes))
continue; // Ignore non-directories
if (find_file_data.cFileName[0] == '.')
continue; // Ignore hidden directories
string child_path = cqe.path + fs_delim + string(find_file_data.cFileName);
if (Stack::is_stack(child_path))
continue; // Ignore leaves.
if (Stack::is_stack(child_path))
{
// Filter out duplicates; first encountered takes precedence
Stack *newp = new Stack(child_path);
//printf("found stack %s\n", child_path.c_str());
// TODO: make this check more efficient
bool dup = false;
for(std::vector<Stack *>::const_iterator it = Stack::stacks.begin();
it != Stack::stacks.end();
it++)
{
if((*it)->name == newp->name)
{
dup=true;
break;
}
}
if(dup)
delete newp;
else
Stack::stacks.push_back(newp);
}
//check to make sure we're allowed to descend
else if (!Stack::is_no_subdirs(child_path))
q.push_front(CrawlQueueEntry(child_path));
}
while (FindNextFile(hfind, &find_file_data) != 0);
DWORD last_error = GetLastError();
FindClose(hfind);
if (last_error != ERROR_NO_MORE_FILES)
{
fprintf(stderr, "[rosstack] FindNextFile error %u while crawling %s\n",
GetLastError(), cqe.path.c_str());
continue;
}
#else
DIR *d = opendir(cqe.path.c_str());
if (!d)
{
@ -1025,6 +1183,7 @@ void ROSStack::crawl_for_stacks(bool force_crawl)
q.push_front(CrawlQueueEntry(child_path));
}
closedir(d);
#endif
}
crawled = true; // don't try to re-crawl if we can't find something
const double crawl_elapsed_time = time_since_epoch() - crawl_start_time;
@ -1033,7 +1192,30 @@ void ROSStack::crawl_for_stacks(bool force_crawl)
char tmp_cache_dir[PATH_MAX];
char tmp_cache_path[PATH_MAX];
strncpy(tmp_cache_dir, cache_path.c_str(), sizeof(tmp_cache_dir));
#if defined(WIN32)
// No dirname on Windows; use _splitpath_s instead
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
_splitpath_s(tmp_cache_dir, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
ext, _MAX_EXT);
char full_dir[_MAX_DRIVE + _MAX_DIR];
_makepath_s(full_dir, _MAX_DRIVE + _MAX_DIR, drive, dir, NULL, NULL);
snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s\\.rosstack_cache.XXXXXX", full_dir);
#else
snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s/.rosstack_cache.XXXXXX", dirname(tmp_cache_dir));
#endif
#if defined(WIN32)
// This one is particularly nasty: on Windows, there is no equivalent of
// mkstemp, so we're stuck with the security risks of mktemp. Hopefully not a
// problem in our use cases.
if (_mktemp_s(tmp_cache_path, PATH_MAX) != 0)
{
fprintf(stderr,
"[rosstack] Unable to generate temporary cache file name: %u",
GetLastError());
throw runtime_error(string("Failed to create tmp cache file name"));
}
FILE *cache = fopen(tmp_cache_path, "w");
#else
int fd = mkstemp(tmp_cache_path);
if (fd < 0)
{
@ -1042,6 +1224,7 @@ void ROSStack::crawl_for_stacks(bool force_crawl)
}
FILE *cache = fdopen(fd, "w");
#endif
if (!cache)
{
fprintf(stderr, "woah! couldn't create the cache file. Please check "
@ -1053,16 +1236,19 @@ void ROSStack::crawl_for_stacks(bool force_crawl)
for (VecStack::iterator s = Stack::stacks.begin();
s != Stack::stacks.end(); ++s)
fprintf(cache, "%s\n", (*s)->path.c_str());
fclose(cache);
if(file_exists(cache_path.c_str()))
remove(cache_path.c_str());
if(rename(tmp_cache_path, cache_path.c_str()) < 0)
{
fprintf(stderr, "[rospack] Error: failed rename cache file %s to %s\n", tmp_cache_path, cache_path.c_str());
perror("rename");
fprintf(stderr,
"[rospack] Error: failed rename cache file %s to %s\n",
tmp_cache_path, cache_path.c_str());
perror("rename");
throw runtime_error(string("failed to rename cache file"));
}
fclose(cache);
if (g_profile_length)
{
// dump it into a stack to reverse it (so slowest guys are first)

View File

@ -82,6 +82,18 @@ distribution.
#endif
#endif
#if defined(WIN32)
#if defined(ROS_STATIC)
#define TINYXML_EXPORT
#elif defined(rospack_EXPORTS) || defined(rosstack_EXPORTS)
#define TINYXML_EXPORT __declspec(dllexport)
#else
#define TINYXML_EXPORT __declspec(dllimport)
#endif
#else
#define TINYXML_EXPORT
#endif
class TiXmlDocument;
class TiXmlElement;
class TiXmlComment;
@ -126,7 +138,7 @@ struct TiXmlCursor
@sa TiXmlNode::Accept()
*/
class TiXmlVisitor
class TINYXML_EXPORT TiXmlVisitor
{
public:
virtual ~TiXmlVisitor() {}
@ -192,7 +204,7 @@ const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
A Decleration contains: Attributes (not on tree)
@endverbatim
*/
class TiXmlBase
class TINYXML_EXPORT TiXmlBase
{
friend class TiXmlNode;
friend class TiXmlElement;
@ -249,7 +261,7 @@ public:
void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data.
const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data.
// Table that returs, for a given lead byte, the total number of bytes
// Table that returns, for a given lead byte, the total number of bytes
// in the UTF-8 sequence.
static const int utf8ByteTable[256];
@ -421,7 +433,7 @@ private:
in a document, or stand on its own. The type of a TiXmlNode
can be queried, and it can be cast to its more defined type.
*/
class TiXmlNode : public TiXmlBase
class TINYXML_EXPORT TiXmlNode : public TiXmlBase
{
friend class TiXmlDocument;
friend class TiXmlElement;
@ -777,7 +789,7 @@ private:
part of the tinyXML document object model. There are other
suggested ways to look at this problem.
*/
class TiXmlAttribute : public TiXmlBase
class TINYXML_EXPORT TiXmlAttribute : public TiXmlBase
{
friend class TiXmlAttributeSet;
@ -901,7 +913,7 @@ private:
- I like circular lists
- it demonstrates some independence from the (typical) doubly linked list.
*/
class TiXmlAttributeSet
class TINYXML_EXPORT TiXmlAttributeSet
{
public:
TiXmlAttributeSet();
@ -941,7 +953,7 @@ private:
and can contain other elements, text, comments, and unknowns.
Elements also contain an arbitrary number of attributes.
*/
class TiXmlElement : public TiXmlNode
class TINYXML_EXPORT TiXmlElement : public TiXmlNode
{
public:
/// Construct an element.
@ -1151,7 +1163,7 @@ private:
/** An XML comment.
*/
class TiXmlComment : public TiXmlNode
class TINYXML_EXPORT TiXmlComment : public TiXmlNode
{
public:
/// Constructs an empty comment.
@ -1201,7 +1213,7 @@ private:
you generally want to leave it alone, but you can change the output mode with
SetCDATA() and query it with CDATA().
*/
class TiXmlText : public TiXmlNode
class TINYXML_EXPORT TiXmlText : public TiXmlNode
{
friend class TiXmlElement;
public:
@ -1274,7 +1286,7 @@ private:
handled as special cases, not generic attributes, simply
because there can only be at most 3 and they are always the same.
*/
class TiXmlDeclaration : public TiXmlNode
class TINYXML_EXPORT TiXmlDeclaration : public TiXmlNode
{
public:
/// Construct an empty declaration.
@ -1343,7 +1355,7 @@ private:
DTD tags get thrown into TiXmlUnknowns.
*/
class TiXmlUnknown : public TiXmlNode
class TINYXML_EXPORT TiXmlUnknown : public TiXmlNode
{
public:
TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {}
@ -1382,7 +1394,7 @@ private:
XML pieces. It can be saved, loaded, and printed to the screen.
The 'value' of a document node is the xml file name.
*/
class TiXmlDocument : public TiXmlNode
class TINYXML_EXPORT TiXmlDocument : public TiXmlNode
{
public:
/// Create an empty document, that has no name.
@ -1631,7 +1643,7 @@ private:
}
@endverbatim
*/
class TiXmlHandle
class TINYXML_EXPORT TiXmlHandle
{
public:
/// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
@ -1730,7 +1742,7 @@ private:
fprintf( stdout, "%s", printer.CStr() );
@endverbatim
*/
class TiXmlPrinter : public TiXmlVisitor
class TINYXML_EXPORT TiXmlPrinter : public TiXmlVisitor
{
public:
TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),