applied windows patch from #3274
This commit is contained in:
parent
3624d67266
commit
d353445182
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 ),
|
||||
|
|
Loading…
Reference in New Issue