diff --git a/tools/rosclean/CMakeLists.txt b/tools/rosclean/CMakeLists.txt index 01deb6c5..0f02ff31 100644 --- a/tools/rosclean/CMakeLists.txt +++ b/tools/rosclean/CMakeLists.txt @@ -1,7 +1,11 @@ project(rosclean) find_package(catkin) + +add_subdirectory(scripts) + install_cmake_infrastructure(${PROJECT_NAME} VERSION 0.0.1 PYTHONPATH src ) + enable_python(${PROJECT_NAME}) diff --git a/tools/rosclean/Makefile b/tools/rosclean/Makefile deleted file mode 100644 index b75b928f..00000000 --- a/tools/rosclean/Makefile +++ /dev/null @@ -1 +0,0 @@ -include $(shell rospack find mk)/cmake.mk \ No newline at end of file diff --git a/tools/rospack/CMakeLists.txt b/tools/rospack/CMakeLists.txt deleted file mode 100644 index dbeac46d..00000000 --- a/tools/rospack/CMakeLists.txt +++ /dev/null @@ -1,134 +0,0 @@ -if(ROSBUILD) - include(rosbuild.cmake) - return() -endif() -# We can't use rosbuild/rosbuild.cmake here, because rosbuild.cmake -# requires rospack, and we're in the process of building rospack. -cmake_minimum_required(VERSION 2.4.6) -set(CMAKE_BUILD_TYPE Release) - -set(CMAKE_OSX_ARCHITECTURES "x86_64") - -set(CMAKE_INSTALL_PREFIX /tmp/rospack) -#set(CMAKE_INSTALL_RPATH_USE_LINK_RPATH true) -#set(CMAKE_SKIP_BUILD_RPATH true) -set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib") -SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") - -include_directories(include ${PROJECT_SOURCE_DIR}) - -# Include the rosbuild's rosconfig.cmake, which includes logic for checking -# for $ROS_ROOT/rosconfig.cmake, where the user may have adjusted the build -# configuration. In particular, that's where static vs. shared is set. -include($ENV{ROS_ROOT}/core/rosbuild/rosconfig.cmake) - -add_definitions(-DTIXML_USE_STL) -set(rospack_sources rospack.cpp - tinyxml-2.5.3/tinystr.cpp - tinyxml-2.5.3/tinyxml.cpp - tinyxml-2.5.3/tinyxmlparser.cpp - tinyxml-2.5.3/tinyxmlerror.cpp) -set(rosstack_sources rosstack.cpp) - -# Here we duplicate a bit of the logic in rosbuild/public.cmake. -if(NOT ROS_BUILD_STATIC_LIBS AND NOT ROS_BUILD_SHARED_LIBS) - message(FATAL_ERROR "Neither shared nor static libraries are enabled. Please set either ROS_BUILD_STATIC_LIBS or ROS_BUILD_SHARED_LIBS to true.") -endif(NOT ROS_BUILD_STATIC_LIBS AND NOT ROS_BUILD_SHARED_LIBS) -if(ROS_BUILD_STATIC_EXES AND ROS_BUILD_SHARED_LIBS) - message(FATAL_ERROR "Static executables are requested, but so are shared libs. This configuration is unsupported. Please either set ROS_BUILD_SHARED_LIBS to false or set ROS_BUILD_STATIC_EXES to false.") -endif(ROS_BUILD_STATIC_EXES AND ROS_BUILD_SHARED_LIBS) - -if(ROS_BUILD_SHARED_LIBS) - # If shared libs are being built, they get the default CMake target name - # No matter what, the libraries get the same name in the end. - add_library(rospack SHARED ${rospack_sources}) - add_library(rosstack SHARED ${rosstack_sources}) - - # Prevent deletion of existing lib of same name - set_target_properties(rospack PROPERTIES CLEAN_DIRECT_OUTPUT 1) - set_target_properties(rosstack PROPERTIES CLEAN_DIRECT_OUTPUT 1) -endif(ROS_BUILD_SHARED_LIBS) - -if(ROS_BUILD_STATIC_LIBS) - add_definitions("-DROS_STATIC") - # If we're only building static libs, then they get the default CMake - # target name. - if(NOT ROS_BUILD_SHARED_LIBS) - set(static_rospack "rospack") - set(static_rosstack "rosstack") - else(NOT ROS_BUILD_SHARED_LIBS) - set(static_rospack "rospack-static") - set(static_rosstack "rosstack-static") - endif(NOT ROS_BUILD_SHARED_LIBS) - - add_library(${static_rospack} STATIC ${rospack_sources}) - add_library(${static_rosstack} STATIC ${rosstack_sources}) - - # Set output name to be the same as shared lib (may not work on Windows) - set_target_properties(${static_rospack} PROPERTIES OUTPUT_NAME "rospack") - set_target_properties(${static_rosstack} PROPERTIES OUTPUT_NAME "rosstack") - # Also add -fPIC, because CMake leaves it out when building static - # libs, even though it's necessary on 64-bit machines for linking this - # lib against shared libs downstream. - set_target_properties(${static_rospack} PROPERTIES COMPILE_FLAGS "-fPIC") - set_target_properties(${static_rosstack} PROPERTIES COMPILE_FLAGS "-fPIC") - - # Prevent deletion of existing lib of same name - set_target_properties(${static_rospack} PROPERTIES CLEAN_DIRECT_OUTPUT 1) - set_target_properties(${static_rosstack} PROPERTIES CLEAN_DIRECT_OUTPUT 1) -endif(ROS_BUILD_STATIC_LIBS) - -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) -set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../bin) - -add_executable(rospackexe main.cpp) -set_target_properties(rospackexe PROPERTIES OUTPUT_NAME rospack) -target_link_libraries(rosstack rospack) -add_executable(rosstackexe rosstack_main.cpp) -set_target_properties(rosstackexe PROPERTIES OUTPUT_NAME rosstack) - -target_link_libraries(rospackexe rospack) -target_link_libraries(rosstackexe rosstack rospack) - -if(ROS_BUILD_STATIC_EXES AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - # This will probably only work on Linux. The LINK_SEARCH_END_STATIC - # property should be sufficient, but it doesn't appear to work - # properly. - set_target_properties(rospackexe PROPERTIES - LINK_FLAGS "-static-libgcc -Wl,-Bstatic") - set_target_properties(rosstackexe PROPERTIES - LINK_FLAGS "-static-libgcc -Wl,-Bstatic") -endif(ROS_BUILD_STATIC_EXES AND ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - -#install(TARGETS rospack rosstack rospackexe rosstackexe -# RUNTIME DESTINATION bin -# LIBRARY DESTINATION lib) -#install(FILES include/rospack/rospack.h -# DESTINATION include/rospack) - -# Prevent warnings about duplicate definition of the targets mentioned -# below -if(COMMAND cmake_policy) - # Logical target names must be globally unique. - cmake_policy(SET CMP0002 OLD) -endif(COMMAND cmake_policy) -# These targets might be called by rosmakeall -add_custom_target(test) -add_custom_target(tests) -add_custom_target(test-results) -add_custom_target(test-future) -add_custom_target(gcoverage) - -######################################### -# Uncomment below for new rospack -#add_library(rp rp.cpp -# tinyxml-2.5.3/tinyxml.cpp -# tinyxml-2.5.3/tinyxmlparser.cpp -# tinyxml-2.5.3/tinyxmlerror.cpp) -#add_executable(rpexe rp_main.cpp) -#set_target_properties(rpexe PROPERTIES OUTPUT_NAME rp) -#target_link_libraries(rpexe rp boost_filesystem boost_system boost_program_options) -#add_executable(rs rs_main.cpp) -#target_link_libraries(rs rp boost_filesystem boost_system) -# Uncomment above for new rospack -######################################### diff --git a/tools/rospack/Makefile b/tools/rospack/Makefile deleted file mode 100644 index 00b43821..00000000 --- a/tools/rospack/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# Can't include cmake.mk because we need rospack to find it, and we're -# trying to build rospack. So we inline a stripped-down version of -# cmake.mk. -#include $(shell rospack find mk)/cmake.mk - -# The all target does the heavy lifting, creating the build directory and -# invoking CMake -all: - @mkdir -p build - -mkdir -p bin - @if ! (cd build && cmake ..); then \ - echo "[rosbuild] CMake failed; trying to clean and start over"; \ - make clean; \ - mkdir -p build; \ - cd build && cmake ..; \ - fi - cd build && make $(PARALLEL_JOBS) - -install: all - cd build && make install - -# The clean target blows everything away -clean: - -cd build && make clean - rm -rf build - -test: all - if cd build && make -k $@; then make test-results; else make test-results && exit 1; fi -tests: all - cd build && make $@ -test-future: all - cd build && make -k $@ -gcoverage: all - cd build && make $@ - -#SRC = main.cpp -#LIBSRC = rospack.cpp \ -# tinyxml-2.5.3/tinystr.cpp \ -# tinyxml-2.5.3/tinyxml.cpp \ -# tinyxml-2.5.3/tinyxmlparser.cpp \ -# tinyxml-2.5.3/tinyxmlerror.cpp -# -# -#OBJ = $(SRC:.cpp=.o) -#LIBOBJ = $(LIBSRC:.cpp=.o) -#OUT = ../../bin/rospack -#LIBOUT = librospack.a -# -#CC=g++ -#AR=ar -#LIBS=-lm -#CFLAGS= -O3 -Wall -fPIC -## For code coverage -##LIBS=-lm -lgcov -##CFLAGS= -O0 -Wall -g -fprofile-arcs -ftest-coverage -#INCLUDES=-I. -# -#default: depend $(OUT) $(LIBOUT) -# -#$(OUT): $(OBJ) $(LIBOUT) -# ${CC} $(OBJ) -o $(OUT) $(LIBS) -L. -lrospack -# -#$(LIBOUT): $(LIBOBJ) -# ${AR} cr $@ $(LIBOBJ) -# -#.cpp.o: -# ${CC} ${CFLAGS} ${INCLUDES} -c $< -o $@ -# -#depend: $(SRC) $(LIBSRC) -# gcc $(INCLUDES) -MM $(SRC) $(LIBSRC) >depend -# -#clean: -# rm -f depend $(OBJ) $(OUT) $(LIBOUT) $(LIBOBJ) -# -#-include depend diff --git a/tools/rospack/include/rospack/rospack.h b/tools/rospack/include/rospack/rospack.h deleted file mode 100644 index 621832d1..00000000 --- a/tools/rospack/include/rospack/rospack.h +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (C) 2008, Morgan Quigley and Willow Garage, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ROSPACK_ROSPACK_H -#define ROSPACK_ROSPACK_H - -/* Author: Morgan Quigley, Brian Gerkey */ - -/** -\mainpage -\htmlinclude manifest.html - -\section overview Overview - -\b %rospack is the ROS package management tool. The %rospack package contains -a single binary, called \b %rospack. - - - Jump to \ref Usage "command-line usage". - -%rospack is part dpkg, part pkg-config. The main function of %rospack is -to crawl through the packages in ROS_ROOT and ROS_PACKAGE_PATH, read and -parse the \b manifest.xml for each package, and assemble a complete -dependency tree for all packages. - -Using this tree, %rospack can answer a number of queries about packages and -their dependencies. Common queries include: - - find : return the absolute path to a package - - depends : return a list of all of a package's dependencies - - depends-on : return a list of packages that depend on the given package - - export : return flags necessary for building and linking against a package - -%rospack is intended to be cross-platform. - -\subsection crawling Crawling algorithm -%rospack crawls in the following order: the directory ROS_ROOT, followed by -the colon-separated list of directories ROS_PACKAGE_PATH, in the order they -are listed. - -During the crawl, %rospack examines the contents of each directory, looking -for a file called @b manifest.xml. If such a file is found, the directory -containing it is considered to be a ROS package, with the package name -equal to the directory name. The crawl does not descend further once a -manifest is found (i.e., packages cannot be nested inside one another). - -If a manifest.xml file is not found in a given directory, each subdirectory -is searched. This subdirectory search is prevented if a file called @b -rospack_nosubdirs is found. The directory itself is still searched for a -manifest, but its subdirectories are not crawled. - -If multiple packages by the same name exist within the search path, the -first one found wins. It is strongly recommended that you keep packages by -the same name in separate trees, each having its own element within -ROS_PACKAGE_PATH. That way, you can deterministically control the search -order by the way that you specify ROS_PACKAGE_PATH. The search order -within a given element of ROS_PACKAGE_PATH can be unpredictably affected by -the details of how files are laid out on disk. - -\subsection efficiency Efficiency considerations -%rospack re-parses the manifest.xml files and rebuilds the dependency tree -on each execution. However, it maintains a cache of package directories in -ROS_ROOT/.rospack_cache. This cache is updated whenever there is a cache -miss, or when the cache is 60 seconds old. You can change this timeout by -setting the environment variable ROS_CACHE_TIMEOUT, in seconds. Set it to -0.0 to force a cache rebuild on every invocation of %rospack. - -%rospack's performance can be adversely affected by the presence of very -broad and/or deep directory structures that don't contain manifest files. -If such directories are in %rospack's search path, it can spend a lot of -time crawling them only to discover that there are no packages to be found. -You can prevent this latency by creating a @b rospack_nosubdirs file in -such directories. If rospack seems to be running annoyingly slowly, you -can use the profile command, which will print out the 20 slowest trees -to crawl (or use profile --length=N to print the slowest N trees). - -\subsection dependencies No dependencies -Because %rospack is the tool that determines dependencies, it cannot depend -on anything else. Thus %rospack contains a copy of the TinyXML library, -instead of using the copy available in 3rdparty. For the same reason, unit -tests for %rospack, which require gtest, are in a separate package, called -rospack_test. - -\section codeapi Code API - -%rospack is used entirely as a command-line tool. While the main -functionality within %rospack is built as a library for testing purposes, -it is not intended for use in writing other applications. Should this -change, the %rospack library API should be cleaned up and better -documented. - -For now, the user-visible API is: - - rospack::ROSPack::ROSPack() - - rospack::ROSPack::run() - -See main.cpp for example usage - -\section rosapi ROS API -%rospack does not expose a ROS API. - -\section commandline Command-line tools - -\subsection rospack rospack - -%rospack is the command-line tool that provides package management services. - -%rospack crawls the directory ROS_ROOT and the colon-separated directories -in ROS_PACKAGE_PATH, determining a directory to be package if it contains a -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 -#include -#include - -#include "tinyxml-2.5.3/tinyxml.h" - -namespace rospack -{ - -class Package; -// global helper functions -void string_split(const std::string &s, std::vector &t, const std::string &d); -bool file_exists(const std::string &fname); -extern const char *fs_delim; -Package *g_get_pkg(const std::string &name); - -typedef std::vector VecPkg; -typedef std::list Acc; -typedef std::list AccList; - -/** - * The Package class contains information about a single 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 pkgs; - static std::vector deleted_pkgs; - - Package(std::string _path); - static bool is_package(std::string path); - static bool is_no_subdirs(std::string path); - const VecPkg &deps1(); - const VecPkg &deps(traversal_order_t order, int depth=0); - std::string manifest_path(); - std::string flags(std::string lang, std::string attrib); - std::string rosdep(); - std::string versioncontrol(); - std::vector > plugins(); - VecPkg descendants1(); - const std::vector &descendants(int depth=0); - rospack_tinyxml::TiXmlElement *manifest_root(); - void accumulate_deps(AccList& acc_list, Package* to); - - /** - * \brief Returns the message flags for this package. If the path/msg or path/srv directories exist, - * adds appropriate compile/link flags depending on what is requested - * \param cflags Whether or not to include compile flags - * \param lflags Whether or not to include link flags - */ - std::string cpp_message_flags(bool cflags, bool lflags); - - -private: - bool deps_calculated, direct_deps_calculated, descendants_calculated; - std::vector _deps, _direct_deps, _descendants; - rospack_tinyxml::TiXmlDocument manifest; - bool manifest_loaded; - - Package(const Package &p) { } // just override the default public one - - bool has_parent(std::string pkg); - const std::vector &direct_deps(bool missing_pkg_as_warning=false); - std::string direct_flags(std::string lang, std::string attrib); - void load_manifest(); -}; - -/** - * The ROSPack class contains information the entire package dependency - * tree. - */ -class ROSPACK_EXPORT ROSPack -{ -public: - static const char* usage(); - - char *ros_root; - - ROSPack(); - - ~ROSPack(); - - Package *get_pkg(std::string pkgname); - - int cmd_depends_on(bool include_indirect); - - int cmd_depends_why(); - - int cmd_find(); - - int cmd_deps(); - - int cmd_depsindent(Package* pkg, int indent); - - int cmd_deps_manifests(); - int cmd_deps_msgsrv(); - - int cmd_deps1(); - - /* - int cmd_predeps(char **args, int args_len); - */ - - std::string snarf_libs(std::string flags, bool invert=false); - std::string snarf_flags(std::string flags, std::string token, bool invert=false); - - int cmd_libs_only(std::string token); - - int cmd_cflags_only(std::string token); - - int cmd_make(char **args, int args_len); - - void export_flags(std::string pkg, std::string lang, std::string attrib); - - int cmd_versioncontrol(int depth); - - int cmd_rosdep(int depth); - - int cmd_export(); - - int cmd_plugins(); - - /** @brief The method that does the work. - * - * Call the run() method with argc and argv to crawl for packages, build - * the tree, and answer the query in the command-line arguments. - * - * @throws std::runtime_error - */ - int run(int argc, char **argv); - - // Another form of run, which takes the arguments as a single string. - // WARNING: this method does naive string-splitting on spaces. - int run(const std::string& cmd); - - // Get the accumulated output - std::string getOutput() { return output_acc; } - - // is -q (quiet) provided ? - bool is_quiet() { return opt_quiet; } - - int cmd_print_package_list(bool print_path); - - int cmd_list_duplicates(); - - int cmd_print_langs_list(); - - void crawl_for_packages(bool force_crawl = false); - VecPkg partial_crawl(const std::string &path); - - // Exposed for testing purposes only - std::string deduplicate_tokens(const std::string& s); - - // Storage for --foo options - // --deps-only - bool opt_deps_only; - // --lang= - std::string opt_lang; - // --attrib= - std::string opt_attrib; - // --length= - std::string opt_length; - // --top= - std::string opt_top; - // The package name - std::string opt_package; - // --target= - std::string opt_target; - // the number of entries to list in the profile table - int opt_profile_length; - // only display zombie directories in profile? - bool opt_profile_zombie_only; - // display warnings about missing dependencies? - bool opt_warn_on_missing_deps; - // display pairs of duplicate packages? - bool opt_display_duplicate_pkgs; - -private: - // is quiet - bool opt_quiet; - bool cache_lock_failed; - bool crawled; - std::string getCachePath(); - // Storage for list of path components, used in add_package. We keep it - // here to avoid reallocation in every run of add_package. - std::vector path_components; - // Add package, filtering out duplicates. - Package* add_package(std::string path); - /** tests if the cache exists, is new enough, and is valid */ - bool cache_is_good(); - /** returns a double representing the seconds since the Epoch */ - static double time_since_epoch(); - /** remove trailing slashes */ - void sanitize_rppvec(std::vector &rppvec); - // Output accumulates here - std::string output_acc; - // A place to store heap-allocated argv, in case we were passed a - // std::string in run(). It'll be freed on destruction. - int my_argc; - char** my_argv; - void freeArgv(); - // Total number of packages found, including duplicates. Used in - // determining whether a directory is a zombie. - int total_num_pkgs; - // Were there any duplicate pkgs found in the crawl? - bool duplicate_packages_found; -}; - -} - -#endif diff --git a/tools/rospack/include/rospack/rosstack.h b/tools/rospack/include/rospack/rosstack.h deleted file mode 100644 index 4a3f9448..00000000 --- a/tools/rospack/include/rospack/rosstack.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2009, Morgan Quigley, Brian Gerkey - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ROSSTACK_ROSSTACK_H -#define ROSSTACK_ROSSTACK_H - -/* Author: Morgan Quigley, Brian Gerkey */ - -/** -\mainpage -\htmlinclude manifest.html - -\section overview Overview - -\b %rosstack is a ROS dependency and distribution tool. The %rosstack package contains -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 -#include - -#include "tinyxml-2.5.3/tinyxml.h" -#include "rospack/rospack.h" - -namespace rosstack -{ - -class ROSSTACK_EXPORT Stack; -// global helper functions -void string_split(const std::string &s, std::vector &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 VecStack; - -/** - * The Stack class contains information about a single stack - */ -class ROSSTACK_EXPORT Stack -{ -public: - enum traversal_order_t { POSTORDER, PREORDER }; - std::string name, path; - static std::vector stacks; - - Stack(std::string _path); - static bool is_stack(const std::string &path); - static bool is_package(const std::string &path); - static bool is_no_subdirs(const std::string &path); - const VecStack &deps1(); - const VecStack &deps(traversal_order_t order, int depth=0); - std::string manifest_path(); - VecStack descendants1(); - const VecStack &descendants(int depth=0); - rospack_tinyxml::TiXmlElement *manifest_root(); - -private: - bool deps_calculated, direct_deps_calculated, descendants_calculated; - VecStack _deps, _direct_deps, _descendants; - rospack_tinyxml::TiXmlDocument manifest; - bool manifest_loaded; - - Stack(const Stack &p) { } // just override the default public one - - bool has_parent(std::string stk); - const VecStack &direct_deps(bool missing_pkg_as_warning=false); - void load_manifest(); -}; - -/** - * The ROSStack class contains information the entire stack dependency - * tree. - */ -class ROSSTACK_EXPORT ROSStack -{ -public: - static const char* usage(); - char *ros_root; - rospack::ROSPack rp; - - ROSStack(); - ~ROSStack(); - Stack *get_stack(const std::string &name); - int cmd_depends_on(bool include_indirect); - int cmd_find(); - int cmd_contains(); - int cmd_contains_path(); - int cmd_deps(); - int cmd_depsindent(Stack* stk, int indent); - int cmd_deps_manifests(); - int cmd_deps1(); - - /** @brief The method that does the work. - * - * Call the run() method with argc and argv to crawl for packages, build - * the tree, and answer the query in the command-line arguments. - * - * @throws std::runtime_error - */ - int run(int argc, char **argv); - - int cmd_print_stack_list(bool print_path); - int cmd_print_packages(); - - void crawl_for_stacks(bool force_crawl = false); - std::string lookup_owner(std::string pkg_name, bool just_owner_name); - void deleteCache(); -private: - bool crawled; - /** tests if the cache exists, is new enough, and is valid */ - void createROSHomeDirectory(); - std::string getCachePath(); - // Add stack, filtering out duplicates. - Stack* add_stack(std::string path); - bool cache_is_good(); - /** returns a double representing the seconds since the Epoch */ - static double time_since_epoch(); - /** remove trailing slashes */ - void sanitize_rppvec(std::vector &rppvec); -}; - -} - -#endif diff --git a/tools/rospack/main.cpp b/tools/rospack/main.cpp deleted file mode 100644 index b6282e27..00000000 --- a/tools/rospack/main.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2008, Morgan Quigley and Willow Garage, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* Author: Morgan Quigley, Brian Gerkey */ - - -#include "rospack/rospack.h" - -#include -#if !defined(WIN32) - #include -#endif -#include - -int main(int argc, char **argv) -{ - if (argc <= 1) - { - fputs(rospack::ROSPack::usage(), stderr); - 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. - // Do the group first, because we can't do it after changing the user. - char* sudo_gid_string = getenv("SUDO_GID"); - if(sudo_gid_string) - { - gid_t sudo_gid = (int)strtol(sudo_gid_string, (char **)NULL, 10); - if(setgid(sudo_gid)) - perror("[rospack] Failed to change GID; cache permissions may need to be adjusted manually. setgid()"); - } - char* sudo_uid_string = getenv("SUDO_UID"); - if(sudo_uid_string) - { - uid_t sudo_uid = (int)strtol(sudo_uid_string, (char **)NULL, 10); - if(setuid(sudo_uid)) - perror("[rospack] Failed to change UID; cache permissions may need to be adjusted manually. setuid()"); - } -#endif - - int ret; - bool quiet; - try - { - // Declare ROSPack instance inside the try block because its - // constructor can throw (e.g., when ROS_ROOT isn't set). - rospack::ROSPack rp; - // Separate try block for running the command, to allow for suppressing - // error output when -q is given. - try - { - ret = rp.run(argc, argv); - printf("%s", rp.getOutput().c_str()); - } - catch(std::runtime_error &e) - { - // Return code is -1 no matter what, but don't rethrow if we were - // asked to be quiet. - ret = -1; - if(!rp.is_quiet()) - throw; - } - } - catch(std::runtime_error &e) - { - fprintf(stderr, "[rospack] %s\n", e.what()); - ret = -1; - } - - return ret; -} diff --git a/tools/rospack/manifest.xml b/tools/rospack/manifest.xml deleted file mode 100644 index ea33c725..00000000 --- a/tools/rospack/manifest.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - -

-rospack is a command-line program which provides many of the services of the *NIX -pkg-config tool. It is used to find packages among the "forest" of code in a -typical ROS distribution, calculate dependencies, mangle Makefiles, and in -general promote peace and harmony in a ROS distribution. -

- -

-rospack uses the TinyXML parser, a zLib-licensed library which is available here: - -http://tinyxml.sourceforge.net -

- -
- Morgan Quigley, Brian Gerkey - BSD - - - - - - - - - - - ${rospack_SOURCE_DIR}/include - ${rospack_SOURCE_DIR} - rospack - - -
diff --git a/tools/rospack/markstack b/tools/rospack/markstack deleted file mode 100755 index 8fb91b48..00000000 --- a/tools/rospack/markstack +++ /dev/null @@ -1,119 +0,0 @@ -#! /usr/bin/env python - -# Copyright (c) 2009, Willow Garage, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of Willow Garage, Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -# Author Tully Foote tfoote@willowgarage.com - -#from __future__ import with_statement - -import os -import re -import distutils.version -import sys, string -import subprocess -import getopt -import roslib -import roslib.rosenv - -from math import sqrt -from optparse import OptionParser - - -def get_all_packages(stack_name): - - try: - # Check version, make postscript if too old to make pdf - args = ["rosstack", "contents", stack_name] - vstr, verr = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() - except subprocess.CalledProcessError: - print >> sys.stderr, "failed to call [rosstack contents %s]"%stack_name - return vstr.split() - - -def mark_uninstalled(packages): - print "uninstalling, ", packages - for p in packages: - filename = os.path.join(roslib.packages.get_pkg_dir(p), "ROS_NOBUILD") - subprocess.check_call(["rm", filename]) - -def mark_installed(packages): - print "installing ", packages - for p in packages: - filename = os.path.join(roslib.packages.get_pkg_dir(p), "ROS_NOBUILD") - subprocess.check_call(["touch", filename]) - -def build_stack(packages): - print "building ", packages - args = ["rosmake"] - args.extend( packages ) - subprocess.check_call(args) - - - -def vdmain(): - parser = OptionParser(usage="usage: %prog [options] [stack1] ... [stackN]", prog='rxdeps') - parser.add_option("-i", "--installed", dest="installed", default=False, - action="store_true", help="Mark Packages as installed") - parser.add_option("-u", "--uninstalled", dest="uninstalled", default=False, - action="store_true", help="Unmark packages as installed") - parser.add_option("-b", "--build", dest="build", default=False, - action="store_true", help="Build all packages in stack") - parser.add_option("--stack_string", dest="stack_string", default=None, - action="store", help="stack name (DEPRECATED)") - parser.add_option("--stack_name", dest="stack_name", default=None, - action="store", help="stack name(DEPRECATED)") - parser.add_option("--stack_version", dest="stack_version", default=None, - action="store", help="stack version(DEPRECATED)") - - options, args = parser.parse_args() - - if options.stack_name: - args.append(options.stack_name) - print "WARNING: --stack_name deprecated use arguments!" - if options.stack_string: - args.append(options.stack_string) - print "WARNING: --stack_string deprecated use arguments!" - if options.stack_version: - print "WARNING: Stack version not used!" - - packages = [] - for s in args: - packages.extend(get_all_packages(s)) - - if options.build: - build_stack(packages) - - if options.installed: - mark_installed(packages) - - elif options.uninstalled: - mark_uninstalled(packages) - - -if __name__ == '__main__': - vdmain() diff --git a/tools/rospack/rosalldeps b/tools/rospack/rosalldeps deleted file mode 100755 index 246e847e..00000000 --- a/tools/rospack/rosalldeps +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - -import os, sys -from optparse import OptionParser - -NAME = 'rosalldeps' - -# Taken from -# http://mail.python.org/pipermail/python-list/2005-November/352658.html -def remove_dups(L): - """Removes duplicate items from list L in place.""" - # Work backwards from the end of the list. - for i in range(len(L)-1, -1, -1): - # Check to see if the current item exists elsewhere in - # the list, and if it does, delete it. - if L[i] in L[:i]: - del L[i] - -def go(pkg, height): - children = os.popen('rospack deps ' + pkg).readlines() - if height == -1: - parents = os.popen('rospack depends-on ' + pkg).readlines() - elif height == 1: - parents = os.popen('rospack depends-on1 ' + pkg).readlines() - - siblings = [] - - for p in parents: - siblings.extend(os.popen('rospack deps ' + p)) - - alldeps = [] - - alldeps.extend(children) - alldeps.extend(siblings) - alldeps.extend([pkg]) - alldeps.extend(parents) - - remove_dups(alldeps) - - for d in alldeps: - dir = os.popen('rospack find ' + d).readlines()[0].strip() - if os.path.exists(os.path.join(dir,'ROS_BUILD_BLACKLIST')) or \ - os.path.exists(os.path.join(dir,'ROS_NOBUILD')) or \ - not os.path.exists(os.path.join(dir,'Makefile')): - continue - else: - print d.strip() - -if __name__ == '__main__': - parser = OptionParser(usage="usage: %prog [options] ", prog=NAME) - parser.add_option("-H", "--height", - dest="height", default=None, - help="Limit maximum height of depends-on build (either 1 or -1)") - (options, args) = parser.parse_args(sys.argv) - - if len(args) != 2: - parser.error('package must be specified') - - pkg = args[1] - height = -1 - if options.height: - height = int(options.height) - if height != 1 and height != -1: - parser.error('height must be 1 or -1') - - go(pkg, height) diff --git a/tools/rospack/rosallpkgs b/tools/rospack/rosallpkgs deleted file mode 100755 index f5ad7b31..00000000 --- a/tools/rospack/rosallpkgs +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -USAGE = 'USAGE: rosallpkgs [pkg1 pkg2...]' - -# Taken from -# http://mail.python.org/pipermail/python-list/2005-November/352658.html -def remove_dups(L): - """Removes duplicate items from list L in place.""" - # Work backwards from the end of the list. - for i in range(len(L)-1, -1, -1): - # Check to see if the current item exists elsewhere in - # the list, and if it does, delete it. - if L[i] in L[:i]: - del L[i] - -import os, sys - -if len(sys.argv) > 1: - pkgs = sys.argv[1:] -else: - pkgs = os.popen('rospack list-names').readlines() - -alldeps = [] -for pkg in pkgs: - children = os.popen('rospack deps ' + pkg).readlines() - alldeps.extend(children) - alldeps.extend([pkg]) - -remove_dups(alldeps) - -for d in alldeps: - print d.strip() diff --git a/tools/rospack/rosbuild.cmake b/tools/rospack/rosbuild.cmake deleted file mode 100644 index 514b80dc..00000000 --- a/tools/rospack/rosbuild.cmake +++ /dev/null @@ -1,37 +0,0 @@ -include(${CMAKE_CURRENT_BINARY_DIR}/package.cmake) - -include_directories(include ${PROJECT_SOURCE_DIR}) - -add_definitions(-DTIXML_USE_STL) -if(ROS_BUILD_STATIC_LIBS) - add_definitions("-DROS_STATIC") -endif() - -set(rospack_sources rospack.cpp - tinyxml-2.5.3/tinystr.cpp - tinyxml-2.5.3/tinyxml.cpp - tinyxml-2.5.3/tinyxmlparser.cpp - tinyxml-2.5.3/tinyxmlerror.cpp) - -set(rosstack_sources rosstack.cpp) - -rosbuild_add_library(rospack ${rospack_sources}) -rosbuild_add_library(rosstack ${rosstack_sources}) - -rosbuild_add_executable(rospackexe main.cpp) -set_target_properties(rospackexe PROPERTIES OUTPUT_NAME rospack) -target_link_libraries(rosstack rospack) - -rosbuild_add_executable(rosstackexe rosstack_main.cpp) -set_target_properties(rosstackexe PROPERTIES OUTPUT_NAME rosstack) -target_link_libraries(rospackexe rospack) -target_link_libraries(rosstackexe rosstack rospack) - -install(TARGETS rospack rosstack rospackexe rosstackexe - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) - -install(FILES include/rospack/rospack.h - DESTINATION include/rospack) - diff --git a/tools/rospack/roscachesvncert b/tools/rospack/roscachesvncert deleted file mode 100755 index d6fc0b6e..00000000 --- a/tools/rospack/roscachesvncert +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -pkgs=`rospack list-names` - -vcs= -for p in $pkgs; do - vc=`rospack vcs0 $p | sed 's/type: svn.*url: \([ ]*\)/\1/g'` - for v in $vc; do - vcs+=$v - vcs+=' ' - done -done - -for v in $vcs; do - if ! (echo p | svn info $v); then - echo "Warning: failed to cache certificate for $v" - fi -done diff --git a/tools/rospack/rospack.cpp b/tools/rospack/rospack.cpp deleted file mode 100644 index ba1f6a77..00000000 --- a/tools/rospack/rospack.cpp +++ /dev/null @@ -1,2308 +0,0 @@ -/* - * Copyright (C) 2008, Morgan Quigley and Willow Garage, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* Author: Morgan Quigley, Brian Gerkey */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(WIN32) - #include - #include - #include - #include -#endif -#include -#include -#include -#include - - -#if defined(_MSC_VER) // msvc only - #define F_OK 0x00 -#else // non msvc only - #include -#endif - -#if defined(WIN32) // - #include - #include // For struct timeval (that's awful) - #include - #include - #include - #include - #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 -#endif - - -#include "tinyxml-2.5.3/tinyxml.h" -#include "rospack/rospack.h" -using namespace std; - -//#define VERBOSE_DEBUG -const double DEFAULT_MAX_CACHE_AGE = 60.0; // rebuild cache every minute -const int MAX_DEPENDENCY_TREE_DEPTH = 1000; // used to detect cycles -const int MAX_DIRECTORY_DEPTH = 1000; // used to detect self-referencing symlinks - - -#include -#ifndef S_ISDIR - #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 -{ - -ROSPack *g_rospack = NULL; // singleton - -#ifdef __APPLE__ - const string g_ros_os("osx"); -#else - #if defined(WIN32) - const string g_ros_os("win32"); - #else - const string g_ros_os("linux"); - #endif -#endif - -#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), - descendants_calculated(false), manifest_loaded(false) -{ - vector name_tokens; - string_split(path, name_tokens, fs_delim); - name = name_tokens.back(); -} -bool Package::is_package(string path) -{ - return file_exists(path + string(fs_delim) + "manifest.xml"); -} -bool Package::is_no_subdirs(string path) -{ - return file_exists(path + string(fs_delim) + "rospack_nosubdirs"); -} -const VecPkg &Package::deps1() -{ - return direct_deps(); -} -const VecPkg &Package::deps(traversal_order_t order, int depth) -{ - if (depth > MAX_DEPENDENCY_TREE_DEPTH) - { - fprintf(stderr,"[rospack] woah! expanding the dependency tree made it blow " - "up.\n There must be a circular dependency somewhere.\n"); - throw runtime_error(string("circular dependency")); - } - if (deps_calculated) - return _deps; - // postorder traversal of the dependency tree - VecPkg my_dd = direct_deps(); - for (VecPkg::iterator i = my_dd.begin(); i != my_dd.end(); ++i) - { - VecPkg d = (*i)->deps(order, depth+1); // recurse on direct dependencies - if (order == PREORDER) - _deps.push_back(*i); - for (VecPkg::iterator j = d.begin(); j != d.end(); ++j) - { - // don't add things twice, but if you have something already - // and we're doing a quasi-preorder traversal, bump it to the back - bool have = false; - VecPkg::iterator prior_loc; - for (VecPkg::iterator k = _deps.begin(); k != _deps.end() && !have; ++k) - if ((*k) == (*j)) - { - prior_loc = k; - have = true; - } - if (have && order == PREORDER) - { - _deps.erase(prior_loc); - _deps.push_back(*j); - } - else if (!have) - _deps.push_back(*j); - } - if (order == POSTORDER) - { - // only stuff it to the end if it isn't there already - bool have = false; - for (VecPkg::iterator k = _deps.begin(); k != _deps.end() && !have; ++k) - if ((*k) == (*i)) - have = true; - if (!have) - _deps.push_back(*i); - } - } - deps_calculated = true; - return _deps; -} -string Package::manifest_path() -{ - return path + string(fs_delim) + "manifest.xml"; -} -string Package::flags(string lang, string attrib) -{ - VecPkg d = deps(PREORDER); - string s; - // Conditionally include this package's exported flags, depending on - // whether --deps-only was given - if(!g_rospack->opt_deps_only) - s += this->direct_flags(lang, attrib) + string(" "); - for (VecPkg::iterator i = d.begin(); i != d.end(); ++i) - { - string f = (*i)->direct_flags(lang, attrib); - if (f.length()) - s += f + string(" "); - } - return s; -} - -string Package::rosdep() -{ - string sd; - rospack_tinyxml::TiXmlElement *mroot = manifest_root(); - for(rospack_tinyxml::TiXmlElement *sd_ele = mroot->FirstChildElement("rosdep"); - sd_ele; - sd_ele = sd_ele->NextSiblingElement("rosdep")) - { - const char *att_str; - if((att_str = sd_ele->Attribute("name"))) - sd += string("name: ") + string(att_str); - sd += string("\n"); - } - - return sd; -} - -string Package::versioncontrol() -{ - string sd; - rospack_tinyxml::TiXmlElement *mroot = manifest_root(); - for(rospack_tinyxml::TiXmlElement *sd_ele = mroot->FirstChildElement("versioncontrol"); - sd_ele; - sd_ele = sd_ele->NextSiblingElement("versioncontrol")) - { - const char *att_str; - if((att_str = sd_ele->Attribute("type"))) - sd += string("type: ") + string(att_str); - if((att_str = sd_ele->Attribute("url"))) - sd += string("\turl: ") + string(att_str); - sd += string("\n"); - } - - return sd; -} - -vector > Package::plugins() -{ - vector > plugins; - - VecPkg deplist; - // If --top=foo was given, then restrict the search to packages that are - // dependencies of foo, plus foo itself - if(g_rospack->opt_top.size()) - { - Package* gtp = g_get_pkg(g_rospack->opt_top); - deplist = gtp->deps(Package::POSTORDER); - deplist.push_back(gtp); - } - - VecPkg desc1 = descendants1(); - desc1.push_back(this); - VecPkg::iterator it = desc1.begin(); - VecPkg::iterator end = desc1.end(); - for (; it != end; ++it) - { - // If we're restricting the search, make sure this package is in the - // deplist. This could be made more efficient. - if(deplist.size()) - { - bool found = false; - for(VecPkg::const_iterator dit = deplist.begin(); - dit != deplist.end(); - dit++) - { - if((*dit)->name == (*it)->name) - { - found = true; - break; - } - } - if(!found) - continue; - } - std::string flags = (*it)->direct_flags(name, g_rospack->opt_attrib); - if (!flags.empty()) - { - plugins.push_back(make_pair((*it)->name, flags)); - } - } - - return plugins; -} - - -VecPkg Package::descendants1() -{ - VecPkg children; - // Make a copy of the pkgs vector, because a crawl can be caused in - // has_parent()->direct_deps()->g_get_pkg()->get_pkg(). That crawl - // will rebuild pkgs, invalidating our iterator, causing esoteric crashes - // e.g., #2056. - VecPkg pkgs_copy(pkgs); - for (VecPkg::iterator p = pkgs_copy.begin(); p != pkgs_copy.end(); ++p) - { - // We catch exceptions here, because we don't care if some - // unrelated packages in the system have invalid manifests - try - { - if ((*p)->has_parent(name)) - children.push_back(*p); - } - catch (runtime_error &e) - { - } - } - return children; -} - -const vector &Package::descendants(int depth) -{ - if (depth > MAX_DEPENDENCY_TREE_DEPTH) - { - fprintf(stderr, "[rospack] woah! circular dependency in the ros tree! aaaaaa!\n"); - throw runtime_error(string("circular dependency")); - } - if (descendants_calculated) - return _descendants; - VecPkg desc_with_dups; - for (VecPkg::iterator p = pkgs.begin(); p != pkgs.end(); ++p) - { - // We catch exceptions here, because we don't care if some - // unrelated packages in the system have invalid manifests - try - { - if ((*p)->has_parent(name)) - { - desc_with_dups.push_back(*p); - const VecPkg &p_desc = (*p)->descendants(depth+1); - for (VecPkg::const_iterator q = p_desc.begin(); - q != p_desc.end(); ++q) - desc_with_dups.push_back(*q); - } - } - catch (runtime_error &e) - { - } - } - _descendants.clear(); - for (VecPkg::iterator p = desc_with_dups.begin(); - p != desc_with_dups.end(); ++p) - { - bool found = false; - for (VecPkg::iterator q = _descendants.begin(); - q != _descendants.end() && !found; ++q) - if ((*q)->name == (*p)->name) - found = true; - if (!found) - _descendants.push_back(*p); - } - descendants_calculated = true; - return _descendants; -} - - -bool Package::has_parent(string pkg) -{ - vector parents = direct_deps(true); - for (VecPkg::iterator i = parents.begin(); i != parents.end(); ++i) - if ((*i)->name == pkg) - return true; - return false; -} - -const vector &Package::direct_deps(bool missing_package_as_warning) -{ - if (direct_deps_calculated) - return _direct_deps; -#ifdef VERBOSE_DEBUG - fprintf(stderr, "calculating direct deps for package [%s]\n", name.c_str()); -#endif - rospack_tinyxml::TiXmlElement *mroot = manifest_root(); - rospack_tinyxml::TiXmlNode *dep_node = 0; - while ((dep_node = mroot->IterateChildren(string("depend"), dep_node))) - { - rospack_tinyxml::TiXmlElement *dep_ele = dep_node->ToElement(); - assert(dep_ele); - const char *dep_pkgname = dep_ele->Attribute("package"); - if (!dep_pkgname) - { - fprintf(stderr,"[rospack] bad depend syntax (no 'package' attribute) in [%s]\n", - manifest_path().c_str()); - throw runtime_error(string("invalid manifest")); - } - else if(dep_pkgname == name) - { - fprintf(stderr,"[rospack] package [%s] depends on itself (%s).\n", - name.c_str(), manifest_path().c_str()); - throw runtime_error(string("self-dependency")); - } - // Must make a copy here, because the call to g_get_pkg() below might - // cause a recrawl, which blows aways the accumulated data structure. - char* dep_pkgname_copy = strdup(dep_pkgname); -#ifdef VERBOSE_DEBUG - fprintf(stderr, "direct_deps: pkg %s has dep %s\n", name.c_str(), dep_pkgname_copy); -#endif - try - { - _direct_deps.push_back(g_get_pkg(dep_pkgname_copy)); - } - catch (runtime_error &e) - { - if (missing_package_as_warning) - { - // Don't warn if we're in certain modes, #2197 - if(g_rospack->opt_warn_on_missing_deps) - { - fprintf(stderr, "[rospack] warning: couldn't find dependency [%s] of [%s]\n", - dep_pkgname_copy, name.c_str()); - } - } - else - { - fprintf(stderr, "[rospack] couldn't find dependency [%s] of [%s]\n", - dep_pkgname_copy, name.c_str()); - free(dep_pkgname_copy); - throw runtime_error(string("missing dependency")); - } - } - free(dep_pkgname_copy); - } - direct_deps_calculated = true; - return _direct_deps; -} - -string Package::cpp_message_flags(bool cflags, bool lflags) -{ - bool msg_exists = file_exists((path + "/msg_gen/generated").c_str()); - bool srv_exists = file_exists((path + "/srv_gen/generated").c_str()); - - string flags; - - if (cflags) - { - if (msg_exists) - { - flags += string(" -I") + path + "/msg_gen/cpp/include"; - } - - if (srv_exists) - { - flags += string(" -I") + path + "/srv_gen/cpp/include"; - } - } - - // lflags not needed until we have a cpp file, but this implementation works, adding -lmsgs and -lsrvs - // we'll probably need to figure out a better way of testing for msg/srvs than just checking if /msg|srv exists though -#if 0 - if (lflags) - { - if (msg_exists) - { - flags += string(" -L") + path + "/lib"; - flags += string(" -Wl,-rpath,") + path + "/lib"; - flags += " -l" + package->name + "msgs"; - } - - if (srv_exists) - { - // if msgs already exist, we'll already have added this to the flags - if (!msg_exists) - { - flags += string(" -L") + path + "/lib"; - flags += string(" -Wl,-rpath,") + path + "/lib"; - } - - flags += " -l" + package->name + "srvs"; - } - } -#endif - - flags += " "; - return flags; -} - -string Package::direct_flags(string lang, string attrib) -{ - rospack_tinyxml::TiXmlElement *mroot = manifest_root(); - rospack_tinyxml::TiXmlElement *export_ele = mroot->FirstChildElement("export"); - string str; - if (export_ele) - { - bool os_match = false; - rospack_tinyxml::TiXmlElement *best_usage = NULL; - for (rospack_tinyxml::TiXmlElement *lang_ele = export_ele->FirstChildElement(lang); - lang_ele; lang_ele = lang_ele->NextSiblingElement(lang)) - { - const char *os_str; - if ((os_str = lang_ele->Attribute("os"))) - { - if(g_ros_os == string(os_str)) - { - if(os_match) - { - fprintf(stderr, "[rospack] warning: ignoring duplicate \"%s\" tag with os=\"%s\" in export block\n", - lang.c_str(), os_str); - } - else - { - best_usage = lang_ele; - os_match = true; - } - } - } - if(!os_match) - { - if (!best_usage) - best_usage = lang_ele; - else if(!os_str) - { - fprintf(stderr, "[rospack] warning: ignoring duplicate \"%s\" tag in export block\n", - lang.c_str()); - } - } - } - // If we found some exported text, then start parsing it. Either way, - // we end up at the logic at the bottom that will conditionally - // append msg_gen / srv_gen includes. This structure was changed to - // fix #3018. - if (best_usage) - { - const char *cstr = best_usage->Attribute(attrib.c_str()); - if (cstr) - { - str = cstr; - while (1) // every decent C program has a while(1) in it - { - int i = str.find(string("${prefix}")); - if (i < 0) - break; // no more occurrences - str.replace(i, string("${prefix}").length(), path); - } - - // Do backquote substitution. E.g., if we find this string: - // `pkg-config --cflags gdk-pixbuf-2.0` - // We replace it with the result of executing the command - // contained within the backquotes (reading from its stdout), which - // might be something like: - // -I/usr/include/gtk-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include - - // Construct and execute the string - // We do the assignment first to ensure that if backquote expansion (or - // anything else) fails, we'll get a non-zero exit status from pclose(). - string cmd = string("ret=\"") + str + string("\" && echo $ret"); - - // Remove embedded newlines - string token("\n"); - for (string::size_type s = cmd.find(token); s != string::npos; - s = cmd.find(token, s)) - { - cmd.replace(s,token.length(),string(" ")); - } - - FILE* p; - if(!(p = popen(cmd.c_str(), "r"))) - { - fprintf(stderr, "[rospack] warning: failed to execute backquote " - "expression \"%s\" in [%s]\n", - cmd.c_str(), manifest_path().c_str()); - string errmsg = string("error in backquote expansion for ") + g_rospack->opt_package; - throw runtime_error(errmsg); - } - else - { - char buf[8192]; - memset(buf,0,sizeof(buf)); - // Read the command's output - do - { - clearerr(p); - while(fgets(buf + strlen(buf),sizeof(buf)-strlen(buf)-1,p)); - } while(ferror(p) && errno == EINTR); - // Close the subprocess, checking exit status - if(pclose(p) != 0) - { - fprintf(stderr, "[rospack] warning: got non-zero exit status from executing backquote expression \"%s\" in [%s]\n", - cmd.c_str(), manifest_path().c_str()); - string errmsg = string("error in backquote expansion for ") + g_rospack->opt_package; - throw runtime_error(errmsg); - } - else - { - // Strip trailing newline, which was added by our call to echo - buf[strlen(buf)-1] = '\0'; - // Replace the backquote expression with the new text - str = string(buf); - } - } - } - } - } - - if (lang == "cpp") - { - if (attrib == "cflags") - { - // Message flags go last so it's possible to override them - str += cpp_message_flags(true, false); - } - else if (attrib == "lflags") - { - // Message flags go last so it's possible to override them - str += cpp_message_flags(false, true); - } - } - - return str; -} - -void Package::load_manifest() -{ - if (manifest_loaded) - return; - if (!manifest.LoadFile(manifest_path())) - { - string errmsg = string("error parsing manifest file at [") + manifest_path().c_str() + string("]"); - fprintf(stderr, "[rospack] warning: error parsing manifest file at [%s]\n", - manifest_path().c_str()); - // Only want this warning printed once. - manifest_loaded = true; - throw runtime_error(errmsg); - } -} - -rospack_tinyxml::TiXmlElement *Package::manifest_root() -{ - load_manifest(); - rospack_tinyxml::TiXmlElement *ele = manifest.RootElement(); - if (!ele) - { - string errmsg = string("error parsing manifest file at [") + manifest_path().c_str() + string("]"); - throw runtime_error(errmsg); - } - return ele; -} - -// Naive recursion. Dynamic programming would be more efficient. -void Package::accumulate_deps(AccList& acc_list, Package* to) -{ - VecPkg dd = direct_deps(); - for(VecPkg::iterator it = dd.begin(); - it != dd.end(); - ++it) - { - if((*it)->name == to->name) - { - Acc acc; - acc.push_back(this); - acc.push_back(to); - acc_list.push_back(acc); - } - else - { - AccList l; - (*it)->accumulate_deps(l, to); - for(AccList::iterator lit = l.begin(); - lit != l.end(); - ++lit) - { - lit->push_front(this); - acc_list.push_back(*lit); - } - } - } -} - -VecPkg Package::pkgs; -VecPkg Package::deleted_pkgs; - -////////////////////////////////////////////////////////////////////////////// - - -ROSPack::ROSPack() : - ros_root(NULL), - opt_deps_only(false), - opt_profile_length(0), - opt_profile_zombie_only(false), - opt_warn_on_missing_deps(true), - opt_display_duplicate_pkgs(false), - opt_quiet(false), - cache_lock_failed(false), - crawled(false), - my_argc(0), - my_argv(NULL), - total_num_pkgs(0), - duplicate_packages_found(false) -{ - g_rospack = this; - Package::pkgs.reserve(500); // get some space to avoid early recopying... - ros_root = getenv("ROS_ROOT"); - if (!ros_root) - { - fprintf(stderr,"[rospack] ROS_ROOT is not defined in the environment.\n"); - throw runtime_error(string("no ROS_ROOT")); - } - if (!file_exists(ros_root)) - { - fprintf(stderr,"[rospack] the path specified as ROS_ROOT is not " - "accessible. Please ensure that this environment variable " - "is set and is writeable by your user account.\n"); - throw runtime_error(string("no ROS_ROOT")); - } - - crawl_for_packages(); -} - -ROSPack::~ROSPack() -{ - for (VecPkg::iterator p = Package::pkgs.begin(); - p != Package::pkgs.end(); ++p) - delete (*p); - Package::pkgs.clear(); - for (VecPkg::iterator p = Package::deleted_pkgs.begin(); - p != Package::deleted_pkgs.end(); ++p) - delete (*p); - Package::deleted_pkgs.clear(); - freeArgv(); -} - -const char* ROSPack::usage() -{ - return "USAGE: rospack [options] [package]\n" - " Allowed commands:\n" - " help\n" - " find [package]\n" - " list\n" - " list-names\n" - " list-duplicates\n" - " langs\n" - " depends [package] (alias: deps)\n" - " depends-manifests [package] (alias: deps-manifests)\n" - " depends-msgsrv [package] (alias: deps-msgsrv)\n" - " depends1 [package] (alias: deps1)\n" - " depends-indent [package] (alias: deps-indent)\n" - " depends-why --target= [package] (alias: deps-why)\n" - " rosdep [package] (alias: rosdeps)\n" - " rosdep0 [package] (alias: rosdeps0)\n" - " vcs [package]\n" - " vcs0 [package]\n" - " depends-on [package]\n" - " depends-on1 [package]\n" - " export [--deps-only] --lang= --attrib= [package]\n" - " plugins --attrib= [--top=] [package]\n" - " cflags-only-I [--deps-only] [package]\n" - " cflags-only-other [--deps-only] [package]\n" - " libs-only-L [--deps-only] [package]\n" - " libs-only-l [--deps-only] [package]\n" - " libs-only-other [--deps-only] [package]\n" - " profile [--length=] [--zombie-only]\n" - " Extra options:\n" - " -q Quiets error reports.\n\n" - " If [package] is omitted, the current working directory\n" - " is used (if it contains a manifest.xml).\n\n"; -} - -Package *ROSPack::get_pkg(string pkgname) -{ - for (VecPkg::iterator p = Package::pkgs.begin(); - p != Package::pkgs.end(); ++p) - { - if ((*p)->name == pkgname) - { - if(!crawled) - { - // Answer come from the cache; check that the path is valid, and - // contains a manifest (#1115). - std::string manifest_path = (*p)->path + fs_delim + "manifest.xml"; - struct stat s; - int ret; - while((ret = stat(manifest_path.c_str(), &s)) != 0 && - errno == EINTR); - if(ret == 0) - { - // Answer looks good - return (*p); - } - else - { - // Bad cache. Warn and fall through to the recrawl below. - fprintf(stderr, "[rospack] warning: invalid cached location %s for package %s; forcing recrawl\n", - (*p)->path.c_str(), - (*p)->name.c_str()); - break; - } - } - else - { - // Answer came from a fresh crawl; no further checking needed. - return (*p); - } - } - } - if (!crawled) // maybe it's a brand-new package. force a crawl. - { - crawl_for_packages(true); // will set the crawled flag; recursion is safe - return get_pkg(pkgname); - } - string errmsg = string("couldn't find package [") + pkgname + string("]"); - throw runtime_error(errmsg); - return NULL; // or not -} - -int ROSPack::cmd_depends_on(bool include_indirect) -{ - // We can't proceed if the argument-parsing logic wasn't able to provide - // any package name. Note that we need to check for an empty opt_package - // here, but not in other places (e.g., cmd_deps()), because here we're - // catching the exception that get_pkg() throws when it can't find the - // package. Elsewhere, we let that exception propagate up. - if(opt_package.size() == 0) - { - string errmsg = string("no package name given, and current directory is not a package root"); - throw runtime_error(errmsg); - } - - // Don't warn about missing deps - opt_warn_on_missing_deps = false; - - // Explicitly crawl for packages, to ensure that we get newly added - // dependent packages. We also avoid the possibility of a recrawl - // happening within the loop below, which could invalidate the pkgs - // vector as we loop over it. - crawl_for_packages(true); - - Package* p; - try - { - p = get_pkg(opt_package); - } - catch(runtime_error) - { - fprintf(stderr, "[rospack] warning: package %s doesn't exist\n", - opt_package.c_str()); - //p = new Package(opt_package); - //Package::pkgs.push_back(p); - p = add_package(opt_package); - } - assert(p); - const VecPkg descendants = include_indirect ? p->descendants() - : p->descendants1(); - for (VecPkg::const_iterator p = descendants.begin(); - p != descendants.end(); ++p) - { - //printf("%s\n", (*p)->name.c_str()); - output_acc += (*p)->name + "\n"; - } - return 0; -} - -// Naive recursion. Dynamic programming would be more efficient. -int ROSPack::cmd_depends_why() -{ - AccList acc_list; - Package* from = get_pkg(opt_package); - Package* to = get_pkg(opt_target); - from->accumulate_deps(acc_list, to); - printf("Dependency chains from %s to %s:\n", - from->name.c_str(), to->name.c_str()); - for(AccList::iterator lit = acc_list.begin(); - lit != acc_list.end(); - ++lit) - { - printf("* "); - for(Acc::iterator ait = lit->begin(); - ait != lit->end(); - ++ait) - { - if(ait != lit->begin()) - printf("-> "); - printf("%s ", (*ait)->name.c_str()); - } - printf("\n"); - } - return 0; -} - -int ROSPack::cmd_find() -{ - // todo: obey the search order - Package *p = get_pkg(opt_package); - //printf("%s\n", p->path.c_str()); - output_acc += ToUnixPathDelim(p->path) + "\n"; - return 0; -} - -int ROSPack::cmd_deps() -{ - VecPkg d = get_pkg(opt_package)->deps(Package::POSTORDER); - for (VecPkg::iterator i = d.begin(); i != d.end(); ++i) - { - //printf("%s\n", (*i)->name.c_str()); - output_acc += ToUnixPathDelim((*i)->name) + "\n"; - } - return 0; -} - -int ROSPack::cmd_deps_manifests() -{ - VecPkg d = get_pkg(opt_package)->deps(Package::POSTORDER); - for (VecPkg::iterator i = d.begin(); i != d.end(); ++i) - { - //printf("%s/manifest.xml ", (*i)->path.c_str()); - output_acc += ToUnixPathDelim((*i)->path + "/manifest.xml "); - } - //puts(""); - output_acc += "\n"; - return 0; -} - -int ROSPack::cmd_deps_msgsrv() -{ - VecPkg d = get_pkg(opt_package)->deps(Package::POSTORDER); - for (VecPkg::iterator i = d.begin(); i != d.end(); ++i) - { - Package* p = *i; - 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 += ToUnixPathDelim(p->path + "/msg_gen/generated "); - } - - if (srv_exists) - { - output_acc += ToUnixPathDelim(p->path + "/srv_gen/generated "); - } - } - output_acc += "\n"; - return 0; -} - -int ROSPack::cmd_deps1() -{ - VecPkg d = get_pkg(opt_package)->deps1(); - for (VecPkg::iterator i = d.begin(); i != d.end(); ++i) - { - //printf("%s\n", (*i)->name.c_str()); - output_acc += ToUnixPathDelim((*i)->name) + "\n"; - } - return 0; -} - -int ROSPack::cmd_depsindent(Package* pkg, int indent) -{ - VecPkg d = pkg->deps1(); - - for (VecPkg::iterator i = d.begin(); i != d.end(); ++i) - { - for(int s=0; sname.c_str()); - output_acc += ToUnixPathDelim((*i)->name) + "\n"; - cmd_depsindent(*i, indent+2); - } - return 0; -} - -/* -int ROSPack::cmd_predeps(char **args, int args_len) -{ - if (args_len != 1) - fprintf(stderr,"[rospack] usage: rospack predeps PACKAGE\n"); - else - { - VecPkg d = get_pkg(args[0])->deps(Package::PREORDER); - for (VecPkg::iterator i = d.begin(); i != d.end(); ++i) - printf("%s\n", (*i)->name.c_str()); - } - return 0; -} -*/ - -static bool space(char c) { return isspace(c); } -static bool not_space(char c) { return !isspace(c); } -static vector split_space(const string& str) -{ - typedef string::const_iterator iter; - vector ret; - iter i = str.begin(); - while (i != str.end()) - { - i = find_if(i, str.end(), not_space); - iter j = find_if(i, str.end(), space); - if (i != str.end()) - while (j != str.end() && *(j-1) == '\\') - j = find_if(j+1, str.end(), space); - ret.push_back(string(i, j)); - i = j; - } - return ret; -} - -string ROSPack::snarf_libs(string flags, bool invert) -{ - vector tokens = split_space(flags); - string snarfed; - for (size_t i = 0; i < tokens.size(); ++i) - { - //fprintf(stderr, "token = %s, len=%d, f=%c last=%s\n", tokens[i].c_str(), tokens[i].length(), tokens[i][0], tokens[i].substr(tokens[i].length()-2).c_str()); - if (invert) - { - if ((tokens[i].substr(0, 2) != "-l") && - (tokens[i].length() < 2 || tokens[i][0] != '/' || tokens[i].substr(tokens[i].length()-2) != ".a")) - snarfed += (snarfed.length() ? " " : "" ) + tokens[i]; - } - else - { - if (tokens[i].substr(0, 2) == "-l") - snarfed += (snarfed.length() ? " " : "" ) + tokens[i].substr(2); - else if (tokens[i].length() > 2 && tokens[i][0] == '/' && tokens[i].substr(tokens[i].length()-2) == ".a") - snarfed += (snarfed.length() ? " " : "" ) + tokens[i]; - } - } - return snarfed; -} - -string ROSPack::snarf_flags(string flags, string prefix, bool invert) -{ - vector tokens = split_space(flags); - string snarfed; - for (size_t i = 0; i < tokens.size(); ++i) - { - if ((tokens[i].substr(0, prefix.length()) == prefix) ^ invert) - { - snarfed += (snarfed.length() ? " " : "" ) + tokens[i].substr(invert ? 0 : prefix.length()); - } - } - return snarfed; -} - -int ROSPack::cmd_libs_only(string token) -{ - string lflags = get_pkg(opt_package)->flags("cpp", "lflags");; - if(!token.compare("-other")) - { - lflags = snarf_libs(lflags, true); - lflags = snarf_flags(lflags, "-L", true); - } - else if(!token.compare("-l")) - { - lflags = snarf_libs(lflags); - } - else - { - lflags = snarf_flags(lflags, token); - lflags = deduplicate_tokens(lflags); - } - //printf("%s\n", lflags.c_str()); - output_acc += ToUnixPathDelim(lflags) + "\n"; - return 0; -} - -int ROSPack::cmd_cflags_only(string token) -{ - string cflags = get_pkg(opt_package)->flags("cpp", "cflags"); - if(!token.compare("-other")) - cflags = snarf_flags(cflags, "-I", true); - else - { - cflags = snarf_flags(cflags, token); - cflags = deduplicate_tokens(cflags); - } - //printf("%s\n", cflags.c_str()); - output_acc += ToUnixPathDelim(cflags) + "\n"; - return 0; -} - -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 += ToUnixPathDelim(flags) + "\n"; -} - -int ROSPack::cmd_versioncontrol(int depth) -{ - string sds; - - sds += get_pkg(opt_package)->versioncontrol(); - - if(depth < 0) - { - VecPkg descs = get_pkg(opt_package)->deps(Package::POSTORDER); - for(VecPkg::iterator dit = descs.begin(); - dit != descs.end(); - dit++) - { - sds += (*dit)->versioncontrol(); - } - } - - //printf("%s", sds.c_str()); - output_acc += sds; - return 0; -} - -int ROSPack::cmd_rosdep(int depth) -{ - string sds; - sds += get_pkg(opt_package)->rosdep(); - - if(depth < 0) - { - VecPkg descs = get_pkg(opt_package)->deps(Package::POSTORDER); - for(VecPkg::iterator dit = descs.begin(); - dit != descs.end(); - dit++) - { - sds += (*dit)->rosdep(); - } - } - - //printf("%s", sds.c_str()); - output_acc += sds; - return 0; -} - -int ROSPack::cmd_export() -{ - export_flags(opt_package, opt_lang, opt_attrib); - return 0; -} - -int ROSPack::cmd_plugins() -{ - // Don't warn about missing deps - opt_warn_on_missing_deps = false; - - Package* p = get_pkg(opt_package); - - vector > plugins = p->plugins(); - vector >::iterator it = plugins.begin(); - vector >::iterator end = plugins.end(); - for (; it != end; ++it) - { - //printf("%s %s\n", it->first.c_str(), it->second.c_str()); - output_acc += it->first + " " + it->second + "\n"; - } - - return 0; -} - -void ROSPack::freeArgv() -{ - if(my_argc) - { - for(int i=0;i cmd_list; - - // TODO: split the input string properly, accounting for quotes, escaped - // quotes, etc. This shouldn't really matter, because rospack shouldn't be - // given arguments with embedded spaces. - string_split(cmd, cmd_list, " "); - - // In case we're called more than once. - freeArgv(); - - my_argc = (int)cmd_list.size() + 1; - my_argv = (char**)malloc(sizeof(char*) * my_argc); - my_argv[0] = strdup("rospack"); - for(int i=1;i= 2); - int i; - const char* opt_deps_name = "--deps-only"; - const char* opt_zombie_name = "--zombie-only"; - const char* opt_lang_name = "--lang="; - const char* opt_attrib_name = "--attrib="; - const char* opt_length_name = "--length="; - const char* opt_top_name = "--top="; - const char* opt_target_name = "--target="; - const char* opt_quiet_name = "-q"; - - // Reset to defaults. - opt_deps_only = false; - // --lang= - opt_lang = string(""); - // --attrib= - opt_attrib = string(""); - // --length= - opt_length = string(""); - // --top= - opt_top = string(""); - // --target= - opt_target = string(""); - // The package name - opt_package = string(""); - // the number of entries to list in the profile table - opt_profile_length = 0; - // only display zombie directories in profile? - opt_profile_zombie_only = false; - // warn on missing deps - opt_warn_on_missing_deps = true; - // don't display duplicate pkgs - opt_display_duplicate_pkgs = false; - - output_acc = string(""); - - string errmsg = string(usage()); - - i=1; - const char* cmd = argv[i++]; - - for(;i strlen(opt_target_name)) - opt_target = string(argv[i]+strlen(opt_target_name)); - else - throw runtime_error(errmsg); - } - else if(!strncmp(argv[i], opt_lang_name, strlen(opt_lang_name))) - { - if(opt_lang.size()) - throw runtime_error(errmsg); - else if(strlen(argv[i]) > strlen(opt_lang_name)) - opt_lang = string(argv[i]+strlen(opt_lang_name)); - else - throw runtime_error(errmsg); - } - else if(!strncmp(argv[i], opt_attrib_name, strlen(opt_attrib_name))) - { - if(opt_attrib.size()) - throw runtime_error(errmsg); - else if(strlen(argv[i]) > strlen(opt_attrib_name)) - opt_attrib = string(argv[i]+strlen(opt_attrib_name)); - else - throw runtime_error(errmsg); - } - else if(!strncmp(argv[i], opt_length_name, strlen(opt_length_name))) - { - if(strlen(argv[i]) > strlen(opt_length_name)) - opt_length = string(argv[i]+strlen(opt_length_name)); - else - throw runtime_error(errmsg); - } - else if(!strncmp(argv[i], opt_top_name, strlen(opt_top_name))) - { - if(strlen(argv[i]) > strlen(opt_top_name)) - opt_top = string(argv[i]+strlen(opt_top_name)); - else - throw runtime_error(errmsg); - } - else - break; - } - - if((strcmp(cmd, "depends-why") && strcmp(cmd, "deps-why")) && opt_target.size()) - throw runtime_error(errmsg); - - if((!strcmp(cmd, "depends-why") || !strcmp(cmd, "deps-why")) && !opt_target.size()) - throw runtime_error(errmsg); - - if(strcmp(cmd, "profile") && (opt_length.size() || opt_profile_zombie_only)) - throw runtime_error(errmsg); - - // --top= is only valid for plugins - if(strcmp(cmd, "plugins") && opt_top.size()) - throw runtime_error(errmsg); - - // --attrib= is only valid for export and plugins - if((strcmp(cmd, "export") && strcmp(cmd, "plugins")) && - opt_attrib.size()) - throw runtime_error(errmsg); - - // --lang= is only valid for export - if((strcmp(cmd, "export") && opt_lang.size())) - throw runtime_error(errmsg); - - // export requires both --lang and --attrib - if(!strcmp(cmd, "export") && (!opt_lang.size() || !opt_attrib.size())) - throw runtime_error(errmsg); - - // plugins requires --attrib - if(!strcmp(cmd, "plugins") && !opt_attrib.size()) - throw runtime_error(errmsg); - - if(opt_deps_only && - strcmp(cmd, "export") && - strcmp(cmd, "cflags-only-I") && - strcmp(cmd, "cflags-only-other") && - strcmp(cmd, "libs-only-L") && - strcmp(cmd, "libs-only-l") && - strcmp(cmd, "libs-only-other")) - throw runtime_error(errmsg); - - if(i < argc) - { - if(!strcmp(cmd, "help") || - !strcmp(cmd, "list") || - !strcmp(cmd, "list-names") || - !strcmp(cmd, "list-duplicates") || - !strcmp(cmd, "langs") || - !strcmp(cmd, "profile")) - throw runtime_error(errmsg); - - opt_package = string(argv[i++]); - } - // Are we sitting in a package? - else - { - char buf[1024]; - if(getcwd(buf,sizeof(buf))) - { - if(Package::is_package(".")) - { -#if defined(_MSC_VER) - // 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 - } - } - } - - if (i != argc) - throw runtime_error(errmsg); - - if (!strcmp(cmd, "profile")) - { - if (opt_length.size()) - opt_profile_length = atoi(opt_length.c_str()); - else - { - if(opt_profile_zombie_only) - opt_profile_length = -1; // default is infinite - else - opt_profile_length = 20; // default is about a screenful or so - } -#ifdef VERBOSE_DEBUG - fprintf(stderr, "profile_length = %d\n", opt_profile_length); -#endif - // re-crawl with profiling enabled - crawl_for_packages(true); - return 0; - } - else if (!strcmp(cmd, "find")) - return cmd_find(); - else if (!strcmp(cmd, "list")) - return cmd_print_package_list(true); - else if (!strcmp(cmd, "list-names")) - return cmd_print_package_list(false); - else if (!strcmp(cmd, "list-duplicates")) - return cmd_list_duplicates(); - else if (!strcmp(cmd, "langs")) - return cmd_print_langs_list(); - else if (!strcmp(cmd, "depends") || !strcmp(cmd, "deps")) - return cmd_deps(); - else if (!strcmp(cmd, "depends-manifests") || !strcmp(cmd, "deps-manifests")) - return cmd_deps_manifests(); - else if (!strcmp(cmd, "depends-msgsrv") || !strcmp(cmd, "deps-msgsrv")) - return cmd_deps_msgsrv(); - else if (!strcmp(cmd, "depends1") || !strcmp(cmd, "deps1")) - return cmd_deps1(); - else if (!strcmp(cmd, "depends-indent") || !strcmp(cmd, "deps-indent")) - return cmd_depsindent(get_pkg(opt_package), 0); - else if (!strcmp(cmd, "depends-on")) - return cmd_depends_on(true); - else if (!strcmp(cmd, "depends-why") || !strcmp(cmd, "deps-why")) - return cmd_depends_why(); - else if (!strcmp(cmd, "depends-on1")) - return cmd_depends_on(false); - /* - else if (!strcmp(argv[i], "predeps")) - return cmd_predeps(argv+i+1, argc-i-1); - */ - else if (!strcmp(cmd, "export")) - return cmd_export(); - else if (!strcmp(cmd, "plugins")) - return cmd_plugins(); - else if (!strcmp(cmd, "rosdep") || !strcmp(cmd, "rosdeps")) - return cmd_rosdep(-1); - else if (!strcmp(cmd, "rosdep0") || !strcmp(cmd, "rosdeps0")) - return cmd_rosdep(0); - else if (!strcmp(cmd, "vcs")) - return cmd_versioncontrol(-1); - else if (!strcmp(cmd, "vcs0")) - return cmd_versioncontrol(0); - else if (!strcmp(cmd, "libs-only-l")) - return cmd_libs_only("-l"); - else if (!strcmp(cmd, "libs-only-L")) - return cmd_libs_only("-L"); - else if (!strcmp(cmd, "libs-only-other")) - return cmd_libs_only("-other"); - else if (!strcmp(cmd, "cflags-only-I")) - return cmd_cflags_only("-I"); - else if (!strcmp(cmd, "cflags-only-other")) - return cmd_cflags_only("-other"); - else if (!strcmp(cmd, "help")) - fputs(usage(), stderr); - else - { - throw runtime_error(errmsg); - } - return 0; -} - -int ROSPack::cmd_print_package_list(bool print_path) -{ - for (VecPkg::iterator i = Package::pkgs.begin(); - i != Package::pkgs.end(); ++i) - if (print_path) - { - //printf("%s %s\n", (*i)->name.c_str(), (*i)->path.c_str()); - output_acc += (*i)->name + " " + (*i)->path + "\n"; - } - else - { - //printf("%s\n", (*i)->name.c_str()); - output_acc += (*i)->name + "\n"; - } - return 0; -} - -int ROSPack::cmd_list_duplicates() -{ - // Force crawl, noting duplicates - opt_display_duplicate_pkgs = true; - crawl_for_packages(true); - // If duplicates were found, return non-zero, because in this mode we - // consider that to be an error. - if(duplicate_packages_found) - return 1; - else - return 0; -} - -int ROSPack::cmd_print_langs_list() -{ - // Don't warn about missing deps - opt_warn_on_missing_deps = false; - - // Check for packages that depend directly on roslang - VecPkg lang_pkgs; - Package* roslang; - - roslang = get_pkg("roslang"); - assert(roslang); - - lang_pkgs = roslang->descendants1(); - - // Filter out packages mentioned in ROS_LANG_DISABLE - char *disable = getenv("ROS_LANG_DISABLE"); - vector disable_list; - if(disable) - string_split(disable, disable_list, ":"); - - for(VecPkg::const_iterator i = lang_pkgs.begin(); - i != lang_pkgs.end(); - ++i) - { - vector::const_iterator j; - for(j = disable_list.begin(); - j != disable_list.end(); - ++j) - { - if((*j) == (*i)->name) - break; - } - if(j == disable_list.end()) - { - //printf("%s ", (*i)->name.c_str()); - output_acc += (*i)->name + " "; - } - } - //printf("\n"); - output_acc += "\n"; - return 0; -} - -string ROSPack::getCachePath() -{ - string cache_file_name; - char* ros_home = getenv("ROS_HOME"); - - if (ros_home) - { - // Create ROS_HOME if it doesn't exist, #2812. - // - // 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)) - { - if(mkdir(ros_home_slash.c_str(), 0700) != 0) - { - perror("[rospack] WARNING: cannot create rospack cache directory"); - } - } - cache_file_name = ros_home_slash + std::string("rospack_cache"); - } - else - { -#if defined(WIN32) - char* home_drive = getenv("HOMEDRIVE"); // getenv owns the memory, don't free these - char* home_path = getenv("HOMEPATH"); - if ( home_drive && home_path ) { - std::string dotros = std::string(getenv("HOMEDRIVE")) + std::string(home_path) + std::string("\\.ros"); - struct stat s; // maybe vista/win7 needs FindFirstFile?? - if(stat(dotros.c_str(), &s)) - { - if(mkdir(dotros.c_str(), 0700) != 0) { - std::cerr << "[rospack] WARNING: cannot create rospack cache directory" << std::endl; - } - } - cache_file_name = dotros + "\\rospack_cache"; - } -#else // UNIX - ros_home = getenv("HOME"); - if (ros_home) - { - // By providing the trailing slash, stat() will only succeed if the - // path exists AND is a directory. - std::string dotros = ros_home + std::string("/.ros/"); - struct stat s; - if(stat(dotros.c_str(), &s)) - { - if(mkdir(dotros.c_str(), 0700) != 0) - perror("[rospack] WARNING: cannot create rospack cache directory"); - } - cache_file_name = dotros + "rospack_cache"; - } -#endif - } - return cache_file_name; -} - -bool ROSPack::cache_is_good() -{ - string cache_path = getCachePath(); - // first see if it's new enough - double cache_max_age = DEFAULT_MAX_CACHE_AGE; - const char *user_cache_time_str = getenv("ROS_CACHE_TIMEOUT"); - if(user_cache_time_str) - cache_max_age = atof(user_cache_time_str); - if(cache_max_age == 0.0) - return false; - struct stat s; - if (stat(cache_path.c_str(), &s) == 0) - { - double dt = difftime(time(NULL), s.st_mtime); -#ifdef VERBOSE_DEBUG - 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. - if ((cache_max_age > 0.0) && (dt > cache_max_age)) - return false; - } - // try to open it - FILE *cache = fopen(cache_path.c_str(), "r"); - if (!cache) - return false; // it's not readable by us. sad. - - // see if ROS_ROOT and ROS_PACKAGE_PATH are identical - char linebuf[30000]; - bool ros_root_ok = false, ros_package_path_ok = false; - const char *ros_package_path = getenv("ROS_PACKAGE_PATH"); - for(;;) - { - if (!fgets(linebuf, sizeof(linebuf), cache)) - break; - linebuf[strlen(linebuf)-1] = 0; // get rid of trailing newline - if (linebuf[0] == '#') - { - if (!strncmp("#ROS_ROOT=", linebuf, 10)) - { - if (!strcmp(linebuf+10, ros_root)) - ros_root_ok = true; - } - else if (!strncmp("#ROS_PACKAGE_PATH=", linebuf, 18)) - { - if (!ros_package_path) - { - if (!strlen(linebuf+18)) - ros_package_path_ok = true; - } - else if (!strcmp(linebuf+18, getenv("ROS_PACKAGE_PATH"))) - ros_package_path_ok = true; - } - } - else - break; // we're out of the header. nothing more matters to this check. - } - fclose(cache); - return ros_root_ok && ros_package_path_ok; -} - -class CrawlQueueEntry -{ -public: - string path; - double start_time, elapsed_time; - size_t start_num_pkgs; - bool has_manifest; - CrawlQueueEntry(string _path) - : path(_path), start_time(0), elapsed_time(0), - start_num_pkgs(0), has_manifest(false){ } - bool operator>(const CrawlQueueEntry &rhs) const - { - return elapsed_time > rhs.elapsed_time; - } -}; - -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(tmpres) / 1e6; -#else - struct timeval tod; - gettimeofday(&tod, NULL); - return tod.tv_sec + 1e-6 * tod.tv_usec; -#endif -} - -// Add package, filtering out duplicates. -Package* ROSPack::add_package(string path) -{ - // Filter out duplicates; first encountered takes precedence - Package* newp = new Package(path); - Package* return_p = newp; - // TODO: make this check more efficient - bool dup = false; - for(std::vector::const_iterator it = Package::pkgs.begin(); - it != Package::pkgs.end(); - it++) - { - if((*it)->name == newp->name) - { - dup=true; - return_p = *it; - // If we're supposed to display info on dups, do it now - if(opt_display_duplicate_pkgs) - output_acc += (*it)->path + " " + newp->path + "\n"; - // Note that we've encountered a duplicate - duplicate_packages_found = true; - break; - } - } - if(dup) - delete newp; - else - Package::pkgs.push_back(newp); - - return return_p; -} - -void ROSPack::crawl_for_packages(bool force_crawl) -{ - for (VecPkg::iterator p = Package::pkgs.begin(); - p != Package::pkgs.end(); ++p) - Package::deleted_pkgs.push_back(*p); - Package::pkgs.clear(); - - if(!force_crawl && cache_is_good()) - { - string cache_path = getCachePath(); - FILE *cache = fopen(cache_path.c_str(), "r"); - if (cache) // one last check just in case nutty stuff happened in between - { -#ifdef VERBOSE_DEBUG - fprintf(stderr, "trying to use cache...\n"); -#endif - char linebuf[30000]; - for(;;) - { - if (!fgets(linebuf, sizeof(linebuf), cache)) - break; // error in read operation - if (linebuf[0] == '#') - continue; - char *newline_pos = strchr(linebuf, '\n'); - if (newline_pos) - *newline_pos = 0; - //Package::pkgs.push_back(new Package(linebuf)); - add_package(linebuf); - } - fclose(cache); - return; // cache load went OK; we're done here. - } - } - // if we get here, this means the cache either bogus or we've been - // instructed to rebuild it. -#ifdef VERBOSE_DEBUG - fprintf(stderr, "building cache\n"); -#endif - deque q; - q.push_back(CrawlQueueEntry(ros_root)); - if (char *rpp = getenv("ROS_PACKAGE_PATH")) - { - vector rppvec; - string_split(rpp, rppvec, path_delim); - sanitize_rppvec(rppvec); - for (vector::iterator i = rppvec.begin(); i != rppvec.end(); ++i) - { - if(!i->size()) - continue; - else if (!Package::is_package(*i) && Package::is_no_subdirs(*i)) - fprintf(stderr, "[rospack] WARNING: non-package directory in " - "ROS_PACKAGE_PATH marked rospack_nosubdirs:\n\t%s\n", - i->c_str()); - else - q.push_back(CrawlQueueEntry(*i)); - } - } - const double crawl_start_time = time_since_epoch(); - priority_queue, - greater > profile; - while (!q.empty()) - { - CrawlQueueEntry cqe = q.front(); - q.pop_front(); - - // Check for maximum depth, #2218. - // Try to avoid repeated allocation. - path_components.reserve(MAX_DIRECTORY_DEPTH+1); - // string_split() will clear() path_components for us - string_split(cqe.path, path_components, fs_delim); - if(path_components.size() > MAX_DIRECTORY_DEPTH) - { - fprintf(stderr,"[rospack] Exceeded maximum directory depth of %d at %s. There must be a self-referencing symlink somewhere.\n", MAX_DIRECTORY_DEPTH, cqe.path.c_str()); - throw runtime_error(string("circular directory structure")); - } - - // Check whether this part of ROS_PACKAGE_PATH is itself a package - if (Package::is_package(cqe.path)) - { - //Package::pkgs.push_back(new Package(*i)); - add_package(cqe.path); - continue; - } - - //printf("crawling %s\n", cqe.path.c_str()); - if (opt_profile_length != 0) - { - if (cqe.start_time != 0) - { - // this stack symbol means we've already crawled its children, and it's - // just here for timing purposes. - - // save the traversal time - cqe.elapsed_time = time_since_epoch() - cqe.start_time; - - // Did the number of packages increase since we started crawling - // this directory's children? If not, then this is likely a zombie - // directory that should probably be deleted. We'll mark it as - // such in the profile console output. - if(cqe.start_num_pkgs < total_num_pkgs) - cqe.has_manifest = true; - if(!opt_profile_zombie_only || !cqe.has_manifest) - { - profile.push(cqe); - if ((opt_profile_length > 0) && (profile.size() > opt_profile_length)) // only save the worst guys - profile.pop(); - } - continue; - } - cqe.start_time = time_since_epoch(); - 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 (find_file_data.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY ) { - 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::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) - { - fprintf(stderr, "[rospack] opendir error [%s] while crawling %s\n", - strerror(errno), cqe.path.c_str()); - continue; - } - struct dirent *ent; - while ((ent = readdir(d)) != NULL) - { - struct stat s; - string child_path = cqe.path + fs_delim + string(ent->d_name); - int ret; - while ((ret = stat(child_path.c_str(), &s)) != 0 && - errno == EINTR); - if (ret != 0) - continue; - if (!S_ISDIR(s.st_mode)) - continue; - if (ent->d_name[0] == '.') - continue; // ignore hidden dirs - if (Package::is_package(child_path)) - { - total_num_pkgs++; - add_package(child_path); - } - //check to make sure we're allowed to descend - else if (!Package::is_no_subdirs(child_path)) - 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; - // Write the results of this crawl to the cache file. At each step, give - // up on error, printing a warning to stderr. - string cache_path(getCachePath()); - if(!cache_path.size()) - { - fprintf(stderr, "[rospack] No location available to write cache file. Try setting ROS_HOME or HOME.\n"); - } - else - { - 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(_MSC_VER) - // 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); -#elif defined(__MINGW32__) - char* temp_name = tempnam(dirname(tmp_cache_dir),".rospack_cache."); - snprintf(tmp_cache_path, sizeof(tmp_cache_path), temp_name); - delete temp_name; -#else - snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s/.rospack_cache.XXXXXX", dirname(tmp_cache_dir)); -#endif -#if defined(__MINGW32__) - // There is no equivalent of mkstemp or _mktemp_s on mingw, so we resort to a slightly problematic - // tempnam (above) and mktemp method. This has the miniscule chance of a race condition. - int fd = open(tmp_cache_path, O_RDWR | O_EXCL | _O_CREAT, 0644); - if (fd < 0) - { - fprintf(stderr, "[rospack] Unable to create temporary cache file %s: %u\n", - tmp_cache_path, errno); - } - else - { - FILE *cache = fdopen(fd, "w"); -#elif defined(WIN32) - 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) - { - fprintf(stderr, "[rospack] Unable to create temporary cache file %s: %s\n", - tmp_cache_path, strerror(errno)); - } - else - { - FILE *cache = fdopen(fd, "w"); -#endif - if (!cache) - { - fprintf(stderr, "[rospack] Unable open cache file %s: %s\n", - tmp_cache_path, strerror(errno)); - } - else - { - char *rpp = getenv("ROS_PACKAGE_PATH"); - fprintf(cache, "#ROS_ROOT=%s\n#ROS_PACKAGE_PATH=%s\n", ros_root, - (rpp ? rpp : "")); - for (VecPkg::iterator pkg = Package::pkgs.begin(); - 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", - tmp_cache_path, cache_path.c_str(), strerror(errno)); - } - } - } - } - - if (opt_profile_length) - { - // dump it into a stack to reverse it (so slowest guys are first) - stack reverse_profile; - // Also build up a separate list of paths that will be used to remove - // children of zombies. - vector zombie_dirs; - zombie_dirs.reserve(profile.size()); - while (!profile.empty()) - { - reverse_profile.push(profile.top()); - zombie_dirs.push_back(profile.top().path); - profile.pop(); - } - if(!opt_profile_zombie_only) - { - //printf("\nFull tree crawl took %.6f seconds.\n", crawl_elapsed_time); - //printf("Directories marked with (*) contain no manifest. You may\n"); - //printf("want to delete these directories.\n"); - //printf("-------------------------------------------------------------\n"); - char buf[16]; - snprintf(buf, sizeof(buf), "%.6f", crawl_elapsed_time); - output_acc += "\nFull tree crawl took " + string(buf) + " seconds.\n"; - output_acc += "Directories marked with (*) contain no manifest. You may\n"; - output_acc += "want to delete these directories.\n"; - output_acc += "To get just of list of directories without manifests,\n"; - output_acc += "re-run the profile with --zombie-only\n."; - output_acc += "-------------------------------------------------------------\n"; - } - while (!reverse_profile.empty()) - { - CrawlQueueEntry cqe = reverse_profile.top(); - reverse_profile.pop(); - - if(!opt_profile_zombie_only) - { - //printf("%.6f %s %s\n", - //cqe.elapsed_time, - //cqe.has_manifest ? " " : "*", - //cqe.path.c_str()); - char buf[16]; - snprintf(buf, sizeof(buf), "%.6f", cqe.elapsed_time); - output_acc += string(buf) + " "; - if(cqe.has_manifest) - output_acc += " "; - else - output_acc += "* "; - output_acc += cqe.path; - output_acc += "\n"; - } - else - { - bool dup = false; - // Does this directory contain a stack.xml or app.xml? In that - // case, it's an empty stack or app, and should not be considered a - // zombie. - if(file_exists(cqe.path + fs_delim + "stack.xml") || - file_exists(cqe.path + fs_delim + "app.xml")) - { - continue; - } - // - // Does this entry's parent appear in the list? - for(vector::const_iterator it = zombie_dirs.begin(); - it != zombie_dirs.end(); - ++it) - { - if((cqe.path.size() > it->size()) && - (cqe.path.substr(0,it->size()) == (*it))) - { - dup = true; - break; - } - } - if(dup) - continue; - - //printf("%s\n", cqe.path.c_str()); - output_acc += cqe.path + "\n"; - } - } - if(!opt_profile_zombie_only) - { - //printf("\n"); - output_acc += "\n"; - } - } -} - -VecPkg ROSPack::partial_crawl(const string &path) -{ - deque q; - q.push_back(CrawlQueueEntry(path)); - VecPkg partial_pkgs; - while (!q.empty()) - { - 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::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) - { - fprintf(stderr, "[rospack] opendir error [%s] while crawling %s\n", - strerror(errno), cqe.path.c_str()); - continue; - } - struct dirent *ent; - while ((ent = readdir(d)) != NULL) - { - struct stat s; - string child_path = cqe.path + fs_delim + string(ent->d_name); - int ret; - while ((ret = stat(child_path.c_str(), &s)) != 0 && - errno == EINTR); - if (ret != 0) - continue; - if (!S_ISDIR(s.st_mode)) - continue; - if (ent->d_name[0] == '.') - continue; // ignore hidden dirs - 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::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)); - } - closedir(d); -#endif - } - return partial_pkgs; -} - -////////////////////////////////////////////////////////////////////////////// - -void string_split(const string &s, vector &t, const string &d) -{ - t.clear(); - size_t start = 0, end; - while ((end = s.find_first_of(d, start)) != string::npos) - { - if((end-start) > 0) - t.push_back(s.substr(start, end-start)); - start = end + 1; - } - if(start < s.size()) - t.push_back(s.substr(start)); -} - -// Produce a new string by keeping only the first of each repeated token in -// the input string, where tokens are space-separated. I'm sure that Rob -// could point me at the Boost/STL one-liner that does the same thing. -string ROSPack::deduplicate_tokens(const string& s) -{ - vector in; - vector out; - string_split(s, in, " "); - for(int i=0; iget_pkg(name); -} - -void ROSPack::sanitize_rppvec(std::vector &rppvec) -{ - // drop any trailing slashes - for (size_t i = 0; i < rppvec.size(); i++) - { - size_t last_slash_pos; - while((last_slash_pos = rppvec[i].find_last_of("/")) == rppvec[i].length()-1) - { - fprintf(stderr, "[rospack] warning: trailing slash found in " - "ROS_PACKAGE_PATH\n"); - rppvec[i].erase(last_slash_pos); - } - } -} - -} diff --git a/tools/rospack/rossearch b/tools/rospack/rossearch deleted file mode 100755 index 7b5bfda3..00000000 --- a/tools/rospack/rossearch +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -# Case-insentive search through all manifests for a term. Returns -# newline-separated list of names of packages that match the search term - -USAGE="USAGE: rossearch " - -if [ $# != 1 ]; then - echo $USAGE - exit -1 -fi - -term=$1 - -pkgdirs=`rospack list | awk {'print \$2'}` - -manifests="" -for d in $pkgdirs; do - mnf="$d/manifest.xml" - if [ ! -f $mnf ]; then - echo "Missing manifest in $d!" - else - manifests="$manifests $mnf" - fi -done - -grepresult=`grep -il "$term" $manifests` - -for g in $grepresult; do - d=`dirname $g` - p=`basename $d` - echo $p -done diff --git a/tools/rospack/rosstack.cpp b/tools/rospack/rosstack.cpp deleted file mode 100644 index ce9c0884..00000000 --- a/tools/rospack/rosstack.cpp +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * Copyright (C) 2009, Morgan Quigley and Brian Gerkey - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* Author: Morgan Quigley, Brian Gerkey */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(WIN32) - #include - #include - #include - #include - #include -#endif -#include -#include -#include -#include - -#if defined(_MSC_VER) // msvc only - #define F_OK 0x00 - #define W_OK 0x02 - #define R_OK 0x04 -#else // non msvc only - #include -#endif - -#if defined(WIN32) // both msvc and mingw - #include - #include - #include - #include - #include - #define PATH_MAX MAX_PATH - #define snprintf _snprintf - #define getcwd _getcwd - #define fdopen _fdopen - #define access _access - #define mkdir(a,b) _mkdir(a) -#endif - -#include "tinyxml-2.5.3/tinyxml.h" -#include "rospack/rosstack.h" -#include "rospack/rospack.h" -using namespace std; - -//#define VERBOSE_DEBUG -const double DEFAULT_MAX_CACHE_AGE = 60.0; // rebuild cache every minute - -#include -#ifndef S_ISDIR -#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) -#endif - -using namespace rosstack; - -#ifdef __APPLE__ -const string g_ros_os("osx"); -#else - #if defined(WIN32) - const string g_ros_os("win32"); - #else - const string g_ros_os("linux"); - #endif -#endif - -#if defined(_MSVC_VER) -// 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 rospack_tinyxml::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 rospack_tinyxml::TiXmlBase::condenseWhiteSpace = true; -#endif - -////////////////////////////////////////////////////////////////////////////// -// Global storage for --foo options -// --deps-only -bool g_deps_only; -// --length= -string g_length; -// The stack name -string g_stack; -// the number of entries to list in the profile table -unsigned int g_profile_length = 0; -// global singleton rosstack pointer... yeah, I know. -ROSStack *g_rosstack = NULL; - -////////////////////////////////////////////////////////////////////////////// - -#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 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 - // will be loaded later, prior to being needed. - //load_manifest(); -} -bool Stack::is_stack(const string &path) -{ - return file_exists(path + string(fs_delim) + "stack.xml"); -} -bool Stack::is_package(const string &path) -{ - return file_exists(path + string(fs_delim) + "manifest.xml"); -} -bool Stack::is_no_subdirs(const string &path) -{ - return file_exists(path + string(fs_delim) + "rosstack_nosubdirs"); -} -const VecStack &Stack::deps1() -{ - return direct_deps(); -} -const VecStack &Stack::deps(traversal_order_t order, int depth) -{ - if (depth > 1000) - { - 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")); - } - if (deps_calculated) - return _deps; - // postorder traversal of the dependency tree - VecStack my_dd = direct_deps(); - for (VecStack::iterator i = my_dd.begin(); i != my_dd.end(); ++i) - { - VecStack d = (*i)->deps(order, depth+1); // recurse on direct dependencies - if (order == PREORDER) - _deps.push_back(*i); - for (VecStack::iterator j = d.begin(); j != d.end(); ++j) - { - // don't add things twice, but if you have something already - // and we're doing a quasi-preorder traversal, bump it to the back - bool have = false; - VecStack::iterator prior_loc; - for (VecStack::iterator k = _deps.begin(); k != _deps.end() && !have; ++k) - if ((*k) == (*j)) - { - prior_loc = k; - have = true; - } - if (have && order == PREORDER) - { - _deps.erase(prior_loc); - _deps.push_back(*j); - } - else if (!have) - _deps.push_back(*j); - } - if (order == POSTORDER) - { - // only stuff it to the end if it isn't there already - bool have = false; - for (VecStack::iterator k = _deps.begin(); k != _deps.end() && !have; ++k) - if ((*k) == (*i)) - have = true; - if (!have) - _deps.push_back(*i); - } - } - deps_calculated = true; - return _deps; -} -string Stack::manifest_path() -{ - return path + string(fs_delim) + "stack.xml"; -} - -VecStack Stack::descendants1() -{ - VecStack children; - for (VecStack::iterator p = stacks.begin(); p != stacks.end(); ++p) - { - // We catch exceptions here, because we don't care if some - // unrelated packages in the system have invalid manifests - try - { - if ((*p)->has_parent(name)) - children.push_back(*p); - } - catch (runtime_error &e) - { - } - } - return children; -} - -const VecStack &Stack::descendants(int depth) -{ - if (depth > 100) - { - fprintf(stderr, "[rosstack] woah! circular dependency! aaaaaa!\n"); - throw runtime_error(string("circular dependency")); - } - if (descendants_calculated) - return _descendants; - VecStack desc_with_dups; - for (VecStack::iterator p = stacks.begin(); p != stacks.end(); ++p) - { - // We catch exceptions here, because we don't care if some - // unrelated packages in the system have invalid manifests - try - { - if ((*p)->has_parent(name)) - { - desc_with_dups.push_back(*p); - const VecStack &p_desc = (*p)->descendants(depth+1); - for (VecStack::const_iterator q = p_desc.begin(); - q != p_desc.end(); ++q) - desc_with_dups.push_back(*q); - } - } - catch (runtime_error &e) - { - } - } - assert(_descendants.size() == 0); - for (VecStack::iterator p = desc_with_dups.begin(); - p != desc_with_dups.end(); ++p) - { - bool found = false; - for (VecStack::iterator q = _descendants.begin(); - q != _descendants.end() && !found; ++q) - if ((*q)->name == (*p)->name) - found = true; - if (!found) - _descendants.push_back(*p); - } - descendants_calculated = true; - return _descendants; -} - - -bool Stack::has_parent(string pkg) -{ - VecStack parents = direct_deps(true); - for (VecStack::iterator i = parents.begin(); i != parents.end(); ++i) - if ((*i)->name == pkg) - return true; - return false; -} - -const VecStack &Stack::direct_deps(bool missing_stack_as_warning) -{ - if (direct_deps_calculated) - return _direct_deps; -#ifdef VERBOSE_DEBUG - printf("calculating direct deps for package [%s]\n", name.c_str()); -#endif - rospack_tinyxml::TiXmlElement *mroot = manifest_root(); - rospack_tinyxml::TiXmlNode *dep_node = 0; - while ((dep_node = mroot->IterateChildren(string("depend"), dep_node))) - { - rospack_tinyxml::TiXmlElement *dep_ele = dep_node->ToElement(); - assert(dep_ele); - const char *dep_stackname = dep_ele->Attribute("stack"); - if (!dep_stackname) - { - fprintf(stderr,"[rosstack] bad depend syntax (no 'stack' attribute) in " - "[%s]\n", manifest_path().c_str()); - throw runtime_error(string("invalid manifest")); - } - // Must make a copy here, because the call to g_get_stack() below might - // cause a recrawl, which blows aways the accumulated data structure. - string dep_stackname_copy = string(dep_stackname); - string name_copy = name; -#ifdef VERBOSE_DEBUG - printf("direct_deps: stk %s has dep %s\n", - name.c_str(), dep_stackname_copy.c_str()); -#endif - try - { - _direct_deps.push_back(g_get_stack(dep_stackname_copy)); - } - catch (runtime_error &e) - { - if (missing_stack_as_warning) - fprintf(stderr, "[rosstack] warning: couldn't find dependency " - "[%s] of [%s]\n", - dep_stackname_copy.c_str(), name_copy.c_str()); - else - { - fprintf(stderr, "[rosstack] couldn't find dependency [%s] of [%s]\n", - dep_stackname_copy.c_str(), name_copy.c_str()); - throw runtime_error(string("missing dependency")); - } - } - } - direct_deps_calculated = true; - return _direct_deps; -} - -void Stack::load_manifest() -{ - if (manifest_loaded) - return; - if (!manifest.LoadFile(manifest_path())) - { - string errmsg = string("error parsing manifest file at [") + manifest_path().c_str() + string("]"); - fprintf(stderr, "[rosstack] warning: error parsing manifest file at [%s]. Blowing away the cache...\n", - manifest_path().c_str()); - g_rosstack->deleteCache(); - // Only want this warning printed once. - manifest_loaded = true; - throw runtime_error(errmsg); - } - rospack_tinyxml::TiXmlElement *mroot = manifest.RootElement(); -} - -rospack_tinyxml::TiXmlElement *Stack::manifest_root() -{ - load_manifest(); - rospack_tinyxml::TiXmlElement *ele = manifest.RootElement(); - if (!ele) - { - string errmsg = string("error parsing manifest file at [") + manifest_path().c_str() + string("]"); - throw runtime_error(errmsg); - } - return ele; -} - -VecStack Stack::stacks; - -////////////////////////////////////////////////////////////////////////////// - - -ROSStack::ROSStack() : ros_root(NULL), crawled(false) -{ - g_rosstack = this; - Stack::stacks.reserve(500); // get some space to avoid early recopying... - ros_root = getenv("ROS_ROOT"); - if (!ros_root) - { - fprintf(stderr,"[rosstack] ROS_ROOT is not defined in the environment.\n"); - throw runtime_error(string("no ROS_ROOT")); - } - if (!file_exists(ros_root)) - { - fprintf(stderr,"[rosstack] the path specified as ROS_ROOT is not " - "accessible. Please ensure that this environment variable " - "is set and is writeable by your user account.\n"); - throw runtime_error(string("no ROS_ROOT")); - } - - createROSHomeDirectory(); - - crawl_for_stacks(); -} - -ROSStack::~ROSStack() -{ - for (VecStack::iterator p = Stack::stacks.begin(); - p != Stack::stacks.end(); ++p) - delete (*p); - Stack::stacks.clear(); -} - -const char* ROSStack::usage() -{ - return "USAGE: rosstack [options] [stack]\n" - " Allowed commands:\n" - " help\n" - " find [stack]\n" - " contents [stack]\n" - " list\n" - " list-names\n" - " depends [stack] (alias: deps)\n" - " depends-manifests [stack] (alias: deps-manifests)\n" - " depends1 [stack] (alias: deps1)\n" - " depends-indent [stack] (alias: deps-indent)\n" - " depends-on [stack]\n" - " depends-on1 [stack]\n" - " contains [package]\n" - " contains-path [package]\n" - " profile [--length=] \n\n" - " If [stack] is omitted, the current working directory\n" - " is used (if it contains a stack.xml).\n\n"; -} - -Stack *ROSStack::get_stack(const string &stack_name) -{ -#ifdef VERBOSE_DEBUG - printf("searching for stack %s\n", stack_name.c_str()); -#endif - for (VecStack::iterator p = Stack::stacks.begin(); - p != Stack::stacks.end(); ++p) - { - if ((*p)->name == stack_name) - { - if(!crawled) - { - // Answer come from the cache; check that the path is valid, and - // contains a manifest (related to #1115). - std::string manifest_path = (*p)->path + fs_delim + "stack.xml"; - struct stat s; - int ret; - while((ret = stat(manifest_path.c_str(), &s)) != 0 && - errno == EINTR); - if(ret == 0) - { - // Answer looks good - return (*p); - } - else - { - // Bad cache. Warn and fall through to the recrawl below. - fprintf(stderr, "[rosstack] warning: invalid cached location %s for package %s; forcing recrawl\n", - (*p)->path.c_str(), - (*p)->name.c_str()); - break; - } - } - else - { - // Answer came from a fresh crawl; no further checking needed. - return (*p); - } - } - } - if (!crawled) // maybe it's a brand-new stack. force a crawl. - { - crawl_for_stacks(true); // will set the crawled flag; recursion is safe - return get_stack(stack_name); - } - throw runtime_error(string("couldn't find stack ") + stack_name); - return NULL; // or not -} - -int ROSStack::cmd_depends_on(bool include_indirect) -{ - // We can't proceed if the argument-parsing logic wasn't able to provide - // any package name. Note that we need to check for an empty opt_package - // here, but not in other places (e.g., cmd_deps()), because here we're - // catching the exception that get_pkg() throws when it can't find the - // package. Elsewhere, we let that exception propagate up. - if(g_stack.size() == 0) - { - string errmsg = string("no stack name given, and current directory is not a stack root"); - throw runtime_error(errmsg); - } - - // Explicitly crawl for stacks, to ensure that we get newly added - // dependent stacks. We also avoid the possibility of a recrawl - // happening within the loop below, which could invalidate the stacks - // vector as we loop over it. - crawl_for_stacks(true); - - Stack* s; - try - { - s = get_stack(g_stack); - } - catch(runtime_error) - { - fprintf(stderr, "[rosstack] warning: stack %s doesn't exist\n", - g_stack.c_str()); - //s = new Stack(g_stack); - //Stack::stacks.push_back(s); - s = add_stack(g_stack); - } - assert(s); - const VecStack descendants = include_indirect ? s->descendants() - : s->descendants1(); - for (VecStack::const_iterator sit = descendants.begin(); - sit != descendants.end(); ++sit) - printf("%s\n", (*sit)->name.c_str()); - return 0; -} - -int ROSStack::cmd_find() -{ - // todo: obey the search order - Stack *p = get_stack(g_stack); - printf("%s\n", p->path.c_str()); - return 0; -} - -string ROSStack::lookup_owner(string pkg_name, bool just_owner_name) -{ - // hack... we'll treat g_stack as the name of the package to look up. - rospack::Package *pkg = rp.get_pkg(pkg_name); -#ifdef VERBOSE_DEBUG - printf("package path: [%s]\n", pkg->path.c_str()); -#endif - map bases; // all the places the search can bottom out - for (VecStack::iterator p = Stack::stacks.begin(); // first, add stacks - p != Stack::stacks.end(); ++p) - bases[(*p)->path] = (*p)->name; - /* - char *rr = getenv("ROS_ROOT"); // add ROS_ROOT - if (rr) - { - bases - } - */ - char *rpp = getenv("ROS_PACKAGE_PATH"); // add ROS_PACKAGE_PATH entries - if (rpp) - { - vector rppvec; - string_split(rpp, rppvec, path_delim); - sanitize_rppvec(rppvec); - for (vector::iterator i = rppvec.begin(); i != rppvec.end(); ++i) - bases[*i] = string(""); - } -#ifdef VERBOSE_DEBUG - printf("bases:\n"); - for (map::iterator i = bases.begin(); i != bases.end(); ++i) - printf("%s -> %s\n", i->first.c_str(), i->second.c_str()); -#endif - // now, chop the package path until we hit one of the bases - string pkg_path_fragment = pkg->path; - while (pkg_path_fragment.length() > 1) - { - // chop off everything to the right of the last slash - size_t last_slash_pos = pkg_path_fragment.find_last_of('/'); - if (last_slash_pos == string::npos) - break; // shouldn't happen, but might as well catch it - pkg_path_fragment = pkg_path_fragment.substr(0, last_slash_pos); -#ifdef VERBOSE_DEBUG - printf("frag = %s\n", pkg_path_fragment.c_str()); -#endif - map::iterator i = bases.find(pkg_path_fragment); - if (i != bases.end()) - { - if (just_owner_name) - return bases[pkg_path_fragment]; - else - return pkg_path_fragment; - break; - } - } - return string(""); -} - -int ROSStack::cmd_contains() -{ - printf("%s\n", lookup_owner(g_stack, true).c_str()); - return 0; -} - -int ROSStack::cmd_contains_path() -{ - printf("%s\n", lookup_owner(g_stack, false).c_str()); - return 0; -} - -int ROSStack::cmd_deps() -{ - VecStack d = get_stack(g_stack)->deps(Stack::POSTORDER); - for (VecStack::iterator i = d.begin(); i != d.end(); ++i) - printf("%s\n", (*i)->name.c_str()); - return 0; -} - -int ROSStack::cmd_deps_manifests() -{ - VecStack d = get_stack(g_stack)->deps(Stack::POSTORDER); - for (VecStack::iterator i = d.begin(); i != d.end(); ++i) - printf("%s/stack.xml ", (*i)->path.c_str()); - puts(""); - return 0; -} - -int ROSStack::cmd_deps1() -{ - VecStack d = get_stack(g_stack)->deps1(); - for (VecStack::iterator i = d.begin(); i != d.end(); ++i) - printf("%s\n", (*i)->name.c_str()); - return 0; -} - -int ROSStack::cmd_depsindent(Stack *stack, int indent) -{ - VecStack d = stack->deps1(); - for (VecStack::iterator i = d.begin(); i != d.end(); ++i) - { - for(int s=0; sname.c_str()); - cmd_depsindent(*i, indent+2); - } - return 0; -} - -static bool space(char c) { return isspace(c); } -static bool not_space(char c) { return !isspace(c); } -static vector split_space(const string& str) -{ - typedef string::const_iterator iter; - vector ret; - iter i = str.begin(); - while (i != str.end()) - { - i = find_if(i, str.end(), not_space); - iter j = find_if(i, str.end(), space); - if (i != str.end()) - ret.push_back(string(i, j)); - i = j; - } - return ret; -} - -int ROSStack::run(int argc, char **argv) -{ - assert(argc >= 2); - int i; - const char* opt_length = "--length="; - - string errmsg = string(usage()); - - i=1; - const char* cmd = argv[i++]; - - for(;i strlen(opt_length)) - g_length = string(argv[i]+strlen(opt_length)); - else - throw runtime_error(errmsg); - } - else - break; - } - - if(strcmp(cmd, "profile") && g_length.size()) - throw runtime_error(errmsg); - - if(i < argc) - { - if(!strcmp(cmd, "help") || - !strcmp(cmd, "list") || - !strcmp(cmd, "list-names") || - !strcmp(cmd, "profile")) - throw runtime_error(errmsg); - g_stack = string(argv[i++]); - } - // Are we sitting in a stack? - else if(Stack::is_stack(".")) - { - char buf[1024]; - if(!getcwd(buf,sizeof(buf))) - throw runtime_error(errmsg); -#if defined(_MSC_VER) - // 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) - throw runtime_error(errmsg); - - if (!strcmp(cmd, "profile")) - { - if (g_length.size()) - g_profile_length = atoi(g_length.c_str()); - else - g_profile_length = 20; // default is about a screenful or so -#ifdef VERBOSE_DEBUG - printf("profile_length = %d\n", g_profile_length); -#endif - // re-crawl with profiling enabled - crawl_for_stacks(true); - return 0; - } - else if (!strcmp(cmd, "find")) - return cmd_find(); - else if (!strcmp(cmd, "contains")) - return cmd_contains(); - else if (!strcmp(cmd, "contains-path")) - return cmd_contains_path(); - else if (!strcmp(cmd, "list")) - return cmd_print_stack_list(true); - else if (!strcmp(cmd, "list-names")) - return cmd_print_stack_list(false); - else if (!strcmp(cmd, "contents")) - return cmd_print_packages(); - else if (!strcmp(cmd, "depends") || !strcmp(cmd, "deps")) - return cmd_deps(); - else if (!strcmp(cmd, "depends-manifests") || !strcmp(cmd, "deps-manifests")) - return cmd_deps_manifests(); - else if (!strcmp(cmd, "depends1") || !strcmp(cmd, "deps1")) - return cmd_deps1(); - else if (!strcmp(cmd, "depends-indent") || !strcmp(cmd, "deps-indent")) - return cmd_depsindent(get_stack(g_stack), 0); - else if (!strcmp(cmd, "depends-on")) - return cmd_depends_on(true); - else if (!strcmp(cmd, "depends-on1")) - return cmd_depends_on(false); - else if (!strcmp(cmd, "help")) - fputs(usage(), stderr); - else - throw runtime_error(errmsg); - return 0; -} - -int ROSStack::cmd_print_stack_list(bool print_path) -{ - for (VecStack::iterator i = Stack::stacks.begin(); - i != Stack::stacks.end(); ++i) - if (print_path) - printf("%s %s\n", (*i)->name.c_str(), (*i)->path.c_str()); - else - printf("%s\n", (*i)->name.c_str()); - return 0; -} - -int ROSStack::cmd_print_packages() -{ - rospack::ROSPack rp; - string path = get_stack(g_stack)->path; - //printf("partial crawl of %s\n", path.c_str()); - rospack::VecPkg pkgs = rp.partial_crawl(path); - //printf("found %d pkgs\n", pkgs.size()); - for (rospack::VecPkg::iterator i = pkgs.begin(); i != pkgs.end(); ++i) - { - printf("%s\n", (*i)->name.c_str()); - delete *i; - } - return 0; -} - -void ROSStack::createROSHomeDirectory() -{ - char *homedir = getenv("HOME"); - if (!homedir) { - //fprintf(stderr, "[rospack] WARNING: cannot create ~/.ros directory.\n"); - } - else - { - string path = string(homedir) + "/.ros"; - if (access(path.c_str(), R_OK) && !mkdir(path.c_str(), 0700)) - fprintf(stderr,"[rosstack] WARNING: cannot create ~/.ros directory.\n"); - } -} - -string ROSStack::getCachePath() -{ - string path; - 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")) + fs_delim + ".ros" + fs_delim + "rosstack_cache"; - return path; -} - -void ROSStack::deleteCache() -{ - string cache_path = g_rosstack->getCachePath(); - if (file_exists(cache_path)) - remove(cache_path.c_str()); -} - -bool ROSStack::cache_is_good() -{ - string cache_path = getCachePath(); - // first see if it's new enough - double cache_max_age = DEFAULT_MAX_CACHE_AGE; - const char *user_cache_time_str = getenv("ROS_CACHE_TIMEOUT"); - if(user_cache_time_str) - cache_max_age = atof(user_cache_time_str); - if(cache_max_age == 0.0) - return false; - struct stat s; - if (stat(cache_path.c_str(), &s) == 0) - { - double dt = difftime(time(NULL), s.st_mtime); -#ifdef VERBOSE_DEBUG - printf("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. - if ((cache_max_age > 0.0) && (dt > cache_max_age)) - return false; - } - // try to open it - FILE *cache = fopen(cache_path.c_str(), "r"); - if (!cache) - return false; // it's not readable by us. sad. - - // see if ROS_ROOT and ROS_PACKAGE_PATH are identical - char linebuf[30000]; - bool ros_root_ok = false, ros_package_path_ok = false; - const char *ros_package_path = getenv("ROS_PACKAGE_PATH"); - while (!feof(cache)) - { - linebuf[0] = 0; - if (!fgets(linebuf, sizeof(linebuf), cache)) - break; - if (!linebuf[0]) - continue; - linebuf[strlen(linebuf)-1] = 0; // get rid of trailing newline - if (linebuf[0] == '#') - { - if (!strncmp("#ROS_ROOT=", linebuf, 10)) - { - if (!strcmp(linebuf+10, ros_root)) - ros_root_ok = true; - } - else if (!strncmp("#ROS_PACKAGE_PATH=", linebuf, 18)) - { - if (!ros_package_path) - { - if (!strlen(linebuf+18)) - ros_package_path_ok = true; - } - else if (!strcmp(linebuf+18, getenv("ROS_PACKAGE_PATH"))) - ros_package_path_ok = true; - } - } - else - break; // we're out of the header. nothing more matters to this check. - } - fclose(cache); - return ros_root_ok && ros_package_path_ok; -} - -class CrawlQueueEntry -{ -public: - string path; - double start_time, elapsed_time; - CrawlQueueEntry(string _path) - : path(_path), start_time(0), elapsed_time(0) { } - bool operator>(const CrawlQueueEntry &rhs) const - { - return elapsed_time > rhs.elapsed_time; - } -}; - -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(tmpres) / 1e6; -#else - struct timeval tod; - gettimeofday(&tod, NULL); - return tod.tv_sec + 1e-6 * tod.tv_usec; -#endif -} - -// Add stack, filtering out duplicates. -Stack* ROSStack::add_stack(string path) -{ - // Filter out duplicates; first encountered takes precedence - Stack* newp = new Stack(path); - Stack* return_p = newp; - // TODO: make this check more efficient - bool dup = false; - for(std::vector::const_iterator it = Stack::stacks.begin(); - it != Stack::stacks.end(); - it++) - { - if((*it)->name == newp->name) - { - dup=true; - return_p = *it; - break; - } - } - if(dup) - delete newp; - else - Stack::stacks.push_back(newp); - - return return_p; -} - -void ROSStack::crawl_for_stacks(bool force_crawl) -{ - for (VecStack::iterator p = Stack::stacks.begin(); - p != Stack::stacks.end(); ++p) - delete *p; - Stack::stacks.clear(); - - if(!force_crawl && cache_is_good()) - { - string cache_path = getCachePath(); - FILE *cache = fopen(cache_path.c_str(), "r"); - if (cache) // one last check just in case nutty stuff happened in between - { -#ifdef VERBOSE_DEBUG - printf("trying to use cache...\n"); -#endif - char linebuf[30000]; - while (!feof(cache)) - { - linebuf[0] = 0; - if (!fgets(linebuf, sizeof(linebuf), cache)) - break; // error in read operation - if (!linebuf[0] || linebuf[0] == '#') - continue; - char *newline_pos = strchr(linebuf, '\n'); - if (newline_pos) - *newline_pos = 0; - //Stack::stacks.push_back(new Stack(linebuf)); - add_stack(linebuf); - } - fclose(cache); - return; // cache load went OK; we're done here. - } - } - // 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"); -#endif - deque q; - q.push_back(CrawlQueueEntry(ros_root)); - vector rspvec; - // seed the crawler with ROS_ROOT and ROS_PACKAGE_PATH - char *rr = getenv("ROS_ROOT"); - if (!rr) - { - fprintf(stderr, "[rosstack] ERROR: ROS_ROOT not set.\n"); - exit(1); - } - // Add the ROS stack - //Stack::stacks.push_back(new Stack(string(rr))); - add_stack(string(rr)); - string rsp; - char *rpp = getenv("ROS_PACKAGE_PATH"); - if (rpp) - rsp = string(rpp); - 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()); -#endif - - for (vector::iterator i = rspvec.begin(); i != rspvec.end(); ++i) - { - if (Stack::is_no_subdirs(*i)) - fprintf(stderr, "[rosstack] WARNING: non-stack directory in " - "ROS_PACKAGE_PATH marked " - "rosstack_nosubdirs:\n\t%s\n", - i->c_str()); - else - q.push_back(CrawlQueueEntry(*i)); - } - const double crawl_start_time = time_since_epoch(); - priority_queue, - greater > profile; - while (!q.empty()) - { - CrawlQueueEntry cqe = q.front(); - q.pop_front(); - - // Check whether this part of ROS_PACKAGE_PATH is itself a package/stack - if (Stack::is_stack(cqe.path)) - { - //Stack::stacks.push_back(new Stack(*i)); - add_stack(cqe.path); - continue; - } - else if (Stack::is_package(cqe.path)) - continue; // ignore it. - - //printf("crawling %s\n", cqe.path.c_str()); - if (g_profile_length > 0) - { - if (cqe.start_time != 0) - { - // this stack symbol means we've already crawled its children, and it's - // just here for timing purposes. save the traversal time and bail. - cqe.elapsed_time = time_since_epoch() - cqe.start_time; - profile.push(cqe); - if (profile.size() > g_profile_length) // only save the worst guys - profile.pop(); - continue; - } - 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::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) - { - fprintf(stderr, "[rosstack] opendir error [%s] while crawling %s\n", - strerror(errno), cqe.path.c_str()); - continue; - } - struct dirent *ent; - while ((ent = readdir(d)) != NULL) - { - struct stat s; - string child_path = cqe.path + fs_delim + string(ent->d_name); - if (stat(child_path.c_str(), &s) != 0) - continue; - if (!S_ISDIR(s.st_mode)) - continue; - if (ent->d_name[0] == '.') - continue; // ignore hidden dirs - else if (Stack::is_stack(child_path)) - { - add_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::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); - */ - } - else if (Stack::is_package(child_path)) - continue; // ignore this guy, he's a leaf. - //check to make sure we're allowed to descend - else if (!Stack::is_no_subdirs(child_path)) - 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; - // write the results of this crawl to the cache file - string cache_path = getCachePath(); - 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(_MSC_VER) - // 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(__MINGW32__) - // There is no equivalent of mkstemp or _mktemp_s on mingw, so we resort to a slightly less secure - // method. Could use mktemp, but as we're just redirecting to FILE anyway, tmpfile() works - // for us. - FILE *cache = tmpfile(); - if ( cache == NULL ) { - fprintf(stderr, - "[rospack] Unable to generate temporary cache file name: %u", - errno); - } -#elif 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) - { - fprintf(stderr, "Unable to create temporary cache file: %s\n", tmp_cache_path); - throw runtime_error(string("failed to create tmp cache file")); - } - - FILE *cache = fdopen(fd, "w"); -#endif - if (!cache) - { - fprintf(stderr, "woah! couldn't create the cache file. Please check " - "ROS_ROOT to make sure it's a writeable directory.\n"); - throw runtime_error(string("failed to create tmp cache file")); - } - - fprintf(cache, "#ROS_ROOT=%s\n#ROS_PACKAGE_PATH=%s\n", ros_root, rsp.c_str()); - 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"); - throw runtime_error(string("failed to rename cache file")); - } - - if (g_profile_length) - { - // dump it into a stack to reverse it (so slowest guys are first) - stack reverse_profile; - while (!profile.empty()) - { - reverse_profile.push(profile.top()); - profile.pop(); - } - printf("\nFull tree crawl took %.6f seconds.\n", crawl_elapsed_time); - printf("-------------------------------------------------------------\n"); - while (!reverse_profile.empty()) - { - CrawlQueueEntry cqe = reverse_profile.top(); - reverse_profile.pop(); - printf("%.6f %s\n", cqe.elapsed_time, cqe.path.c_str()); - } - printf("\n"); - } -} - -////////////////////////////////////////////////////////////////////////////// - -void rosstack::string_split(const string &s, vector &t, const string &d) -{ - t.clear(); - size_t start = 0, end; - while ((end = s.find_first_of(d, start)) != string::npos) - { - t.push_back(s.substr(start, end-start)); - start = end + 1; - } - if (start != s.length()) - t.push_back(s.substr(start)); -} - -bool rosstack::file_exists(const string &fname) -{ - return (access(fname.c_str(), F_OK) == 0); // will be different in windows -} - -Stack *rosstack::g_get_stack(const string &name) -{ - return g_rosstack->get_stack(name); -} - -void ROSStack::sanitize_rppvec(std::vector &rppvec) -{ - // drop any trailing slashes - for (size_t i = 0; i < rppvec.size(); i++) - { - size_t last_slash_pos = rppvec[i].find_last_of("/"); - if (last_slash_pos != string::npos && - last_slash_pos == rppvec[i].length()-1) - { - fprintf(stderr, "[rosstack] warning: trailing slash found in " - "ROS_PACKAGE_PATH\n"); - rppvec[i].erase(last_slash_pos); - } - } -} - diff --git a/tools/rospack/rosstack_main.cpp b/tools/rospack/rosstack_main.cpp deleted file mode 100644 index 72d6323a..00000000 --- a/tools/rospack/rosstack_main.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2009, Morgan Quigley, Brian Gerkey - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* Author: Morgan Quigley, Brian Gerkey */ - - -#include -#include "rospack/rosstack.h" - -int main(int argc, char **argv) -{ - if (argc <= 1) - return (fputs(rosstack::ROSStack::usage(), stderr) < 0); - int ret; - try - { - rosstack::ROSStack rs; - ret = rs.run(argc, argv); - } - catch(std::runtime_error &e) - { - fprintf(stderr, "[rosstack] %s\n", e.what()); - ret = -1; - } - - return ret; -} diff --git a/tools/rospack/rp.cpp b/tools/rospack/rp.cpp deleted file mode 100644 index 38e2c8ae..00000000 --- a/tools/rospack/rp.cpp +++ /dev/null @@ -1,1450 +0,0 @@ -/* - * Copyright (C) 2008, Willow Garage, Inc., Morgan Quigley - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "rp.h" -#include "tinyxml-2.5.3/tinyxml.h" - -#include -#include - -#if defined(WIN32) - #include - #define getcwd _getcwd -#else //!defined(WIN32) - #include - #include - #include - #include - #include - #include -#endif - -#include -#include -#include -#include -#include -#include - -// TODO: -// recrawl on: -// package not found in cache -// package found in cache, but no manifest.xml present in filesystem - -namespace fs = boost::filesystem; - -namespace rospack -{ - -static const char* ROSPACK_MANIFEST_NAME = "manifest.xml"; -static const char* ROSSTACK_MANIFEST_NAME = "stack.xml"; -static const char* ROSPACK_CACHE_NAME = "rospack_cache"; -static const char* ROSSTACK_CACHE_NAME = "rosstack_cache"; -static const char* ROSPACK_NOSUBDIRS = "rospack_nosubdirs"; -static const char* DOTROS_NAME = ".ros"; -static const char* MSG_GEN_GENERATED_DIR = "msg_gen"; -static const char* MSG_GEN_GENERATED_FILE = "generated"; -static const char* SRV_GEN_GENERATED_DIR = "srv_gen"; -static const char* SRV_GEN_GENERATED_FILE = "generated"; -static const char* MANIFEST_TAG_PACKAGE = "package"; -static const char* MANIFEST_TAG_ROSDEP = "rosdep"; -static const char* MANIFEST_TAG_VERSIONCONTROL = "versioncontrol"; -static const char* MANIFEST_TAG_EXPORT = "export"; -static const char* MANIFEST_ATTR_NAME = "name"; -static const char* MANIFEST_ATTR_TYPE = "type"; -static const char* MANIFEST_ATTR_URL = "url"; -static const char* MANIFEST_PREFIX = "${prefix}"; -static const int MAX_CRAWL_DEPTH = 1000; -static const int MAX_DEPENDENCY_DEPTH = 1000; -static const double DEFAULT_MAX_CACHE_AGE = 60.0; - -// Allow ourselves one global, to avoid having to tie the log_* methods -// into the Rosstackage class. -static bool QUIET = false; - -rospack_tinyxml::TiXmlElement* get_manifest_root(Stackage* stackage); -double time_since_epoch(); - -class Exception : public std::runtime_error -{ - public: - Exception(const std::string& what) - : std::runtime_error(what) - {} -}; - -class Stackage -{ - public: - // \brief name of the stackage - std::string name_; - // \brief absolute path to the stackage - std::string path_; - // \brief absolute path to the stackage manifest - std::string manifest_path_; - // \brief have we already loaded the manifest? - bool manifest_loaded_; - // \brief TinyXML structure, filled in during parsing - rospack_tinyxml::TiXmlDocument manifest_; - std::vector deps_; - bool deps_computed_; - - Stackage(const std::string& name, - const std::string& path, - const std::string& manifest_path) : - name_(name), - path_(path), - manifest_path_(manifest_path), - manifest_loaded_(false), - deps_computed_(false) - { - } - -}; - -class DirectoryCrawlRecord -{ - public: - std::string path_; - bool zombie_; - double start_time_; - double crawl_time_; - size_t start_num_pkgs_; - DirectoryCrawlRecord(std::string path, - double start_time, - size_t start_num_pkgs) : - path_(path), - zombie_(false), - start_time_(start_time), - crawl_time_(0.0), - start_num_pkgs_(start_num_pkgs) {} -}; -bool cmpDirectoryCrawlRecord(DirectoryCrawlRecord* i, - DirectoryCrawlRecord* j) -{ - return (i->crawl_time_ < j->crawl_time_); -} - -///////////////////////////////////////////////////////////// -// Rosstackage methods (public/protected) -///////////////////////////////////////////////////////////// -Rosstackage::Rosstackage(std::string manifest_name, - std::string cache_name, - crawl_direction_t crawl_dir, - bool quiet): - manifest_name_(manifest_name), - cache_name_(cache_name), - crawl_dir_(crawl_dir), - crawled_(false) -{ - QUIET = quiet; -} - -bool -Rosstackage::isStackage(const std::string& path) -{ - if(!fs::is_directory(path)) - return false; - - for(fs::directory_iterator dit = fs::directory_iterator(path); - dit != fs::directory_iterator(); - ++dit) - { - if(!fs::is_regular_file(dit->path())) - continue; - - if(dit->path().filename() == manifest_name_) - return true; - } - return false; -} - -void -Rosstackage::crawl(const std::vector& search_path, - bool force) -{ - if(crawled_) - return; - if(!force) - { - if(readCache()) - return; - } - - std::vector dummy; - std::tr1::unordered_set dummy2; - for(std::vector::const_iterator p = search_path.begin(); - p != search_path.end(); - ++p) - { - crawlDetail(*p, force, 1, false, dummy, dummy2); - } - - crawled_ = true; - - writeCache(); -} - -bool -Rosstackage::inStackage(std::string& name) -{ - char path[PATH_MAX]; - if(getcwd(path,sizeof(path))) - { - if(Rosstackage::isStackage(path)) - { -#if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2) - name = fs::path(path).filename(); -#else - // in boostfs3, filename() returns a path, which needs to be stringified - name = fs::path(path).filename().string(); -#endif - return true; - } - } - return false; -} - - -bool -Rosstackage::find(const std::string& name, std::string& path) -{ - std::tr1::unordered_map::const_iterator it = stackages_.find(name); - if(it != stackages_.end()) - { - path = it->second->path_; - return true; - } - else - { - log_error("librospack", std::string("package ") + name + " not found"); - return false; - } -} - -void -Rosstackage::list(std::vector >& list) -{ - list.resize(stackages_.size()); - int i = 0; - for(std::tr1::unordered_map::const_iterator it = stackages_.begin(); - it != stackages_.end(); - ++it) - { - list[i].first = it->first; - list[i].second = it->second->path_; - i++; - } -} - -void -Rosstackage::listDuplicates(std::vector& dups) -{ - dups.resize(dups_.size()); - int i = 0; - for(std::tr1::unordered_set::const_iterator it = dups_.begin(); - it != dups_.end(); - ++it) - { - dups[i] = (*it); - i++; - } -} - -bool -Rosstackage::deps(const std::string& name, bool direct, - std::vector& deps) -{ - std::vector stackages; - if(!depsDetail(name, direct, stackages)) - return false; - for(std::vector::const_iterator it = stackages.begin(); - it != stackages.end(); - ++it) - deps.push_back((*it)->name_); - return true; -} - -bool -Rosstackage::dependsOn(const std::string& name, bool direct, - std::vector& deps) -{ - std::vector stackages; - if(!dependsOnDetail(name, direct, stackages)) - return false; - for(std::vector::const_iterator it = stackages.begin(); - it != stackages.end(); - ++it) - deps.push_back((*it)->name_); - return true; -} - -bool -Rosstackage::depsIndent(const std::string& name, bool direct, - std::vector& deps) -{ - if(!stackages_.count(name)) - { - log_error("librospack", std::string("no such package ") + name); - return false; - } - Stackage* stackage = stackages_[name]; - try - { - computeDeps(stackage); - std::vector deps_vec; - std::tr1::unordered_set deps_hash; - std::vector indented_deps; - gatherDepsFull(stackage, direct, POSTORDER, 0, deps_hash, deps_vec, true, indented_deps); - for(std::vector::const_iterator it = indented_deps.begin(); - it != indented_deps.end(); - ++it) - deps.push_back(*it); - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -bool -Rosstackage::depsManifests(const std::string& name, bool direct, - std::vector& manifests) -{ - if(!stackages_.count(name)) - { - log_error("librospack", std::string("no such package ") + name); - return false; - } - Stackage* stackage = stackages_[name]; - try - { - computeDeps(stackage); - std::vector deps_vec; - gatherDeps(stackage, direct, POSTORDER, deps_vec); - for(std::vector::const_iterator it = deps_vec.begin(); - it != deps_vec.end(); - ++it) - manifests.push_back((*it)->manifest_path_); - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -bool -Rosstackage::rosdeps(const std::string& name, bool direct, - std::vector& rosdeps) -{ - if(!stackages_.count(name)) - { - log_error("librospack", std::string("no such package ") + name); - return false; - } - Stackage* stackage = stackages_[name]; - try - { - computeDeps(stackage); - std::vector deps_vec; - // rosdeps include the current package - deps_vec.push_back(stackage); - if(!direct) - gatherDeps(stackage, direct, POSTORDER, deps_vec); - for(std::vector::const_iterator it = deps_vec.begin(); - it != deps_vec.end(); - ++it) - { - rospack_tinyxml::TiXmlElement* root = get_manifest_root(*it); - for(rospack_tinyxml::TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_ROSDEP); - ele; - ele = ele->NextSiblingElement(MANIFEST_TAG_ROSDEP)) - { - const char *att_str; - if((att_str = ele->Attribute(MANIFEST_ATTR_NAME))) - { - rosdeps.push_back(std::string("name: ") + att_str); - } - } - } - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -bool -Rosstackage::vcs(const std::string& name, bool direct, - std::vector& vcs) -{ - if(!stackages_.count(name)) - { - log_error("librospack", std::string("no such package ") + name); - return false; - } - Stackage* stackage = stackages_[name]; - try - { - computeDeps(stackage); - std::vector deps_vec; - // vcs include the current package - deps_vec.push_back(stackage); - if(!direct) - gatherDeps(stackage, direct, POSTORDER, deps_vec); - for(std::vector::const_iterator it = deps_vec.begin(); - it != deps_vec.end(); - ++it) - { - rospack_tinyxml::TiXmlElement* root = get_manifest_root(*it); - for(rospack_tinyxml::TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_VERSIONCONTROL); - ele; - ele = ele->NextSiblingElement(MANIFEST_TAG_VERSIONCONTROL)) - { - std::string result; - const char *att_str; - if((att_str = ele->Attribute(MANIFEST_ATTR_TYPE))) - { - result.append("type: "); - result.append(att_str); - } - if((att_str = ele->Attribute(MANIFEST_ATTR_URL))) - { - result.append("\turl: "); - result.append(att_str); - } - vcs.push_back(result); - } - } - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -bool -Rosstackage::exports(const std::string& name, const std::string& lang, - const std::string& attrib, bool deps_only, - std::vector& flags) -{ - if(!stackages_.count(name)) - { - log_error("librospack", std::string("no such package ") + name); - return false; - } - Stackage* stackage = stackages_[name]; - try - { - computeDeps(stackage); - std::vector deps_vec; - if(!deps_only) - deps_vec.push_back(stackage); - gatherDeps(stackage, false, PREORDER, deps_vec); - for(std::vector::const_iterator it = deps_vec.begin(); - it != deps_vec.end(); - ++it) - { - rospack_tinyxml::TiXmlElement* root = get_manifest_root(*it); - for(rospack_tinyxml::TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_EXPORT); - ele; - ele = ele->NextSiblingElement(MANIFEST_TAG_EXPORT)) - { - for(rospack_tinyxml::TiXmlElement* ele2 = ele->FirstChildElement(lang); - ele2; - ele2 = ele2->NextSiblingElement(lang)) - { - const char *att_str; - if((att_str = ele2->Attribute(attrib.c_str()))) - { - std::string expanded_str; - if(!expandExportString(*it, att_str, expanded_str)) - return false; - flags.push_back(expanded_str); - } - } - } - - // We automatically point to msg_gen and msg_srv directories if - // certain files are present - fs::path msg_gen = fs::path((*it)->path_) / MSG_GEN_GENERATED_DIR; - fs::path srv_gen = fs::path((*it)->path_) / SRV_GEN_GENERATED_DIR; - if(fs::is_regular_file(msg_gen / MSG_GEN_GENERATED_FILE)) - { - msg_gen /= fs::path("cpp") / "include"; - flags.push_back(std::string("-I" + msg_gen.string())); - } - if(fs::is_regular_file(srv_gen / SRV_GEN_GENERATED_FILE)) - { - srv_gen /= fs::path("cpp") / "include"; - flags.push_back(std::string("-I" + srv_gen.string())); - } - } - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -bool -Rosstackage::plugins(const std::string& name, const std::string& attrib, - const std::string& top, - std::vector& flags) -{ - // Find everybody who depends directly on the package in question - std::vector stackages; - if(!dependsOnDetail(name, true, stackages)) - return false; - // If top was given, filter to include only those package on which top - // depends. - if(top.size()) - { - std::vector top_deps; - if(!depsDetail(top, false, top_deps)) - return false; - std::tr1::unordered_set top_deps_set; - for(std::vector::iterator it = top_deps.begin(); - it != top_deps.end(); - ++it) - top_deps_set.insert(*it); - std::vector::iterator it = stackages.begin(); - while(it != stackages.end()) - { - if((*it)->name_ != top && - (top_deps_set.find(*it) == top_deps_set.end())) - it = stackages.erase(it); - else - ++it; - } - } - // Now go looking for the manifest data - for(std::vector::const_iterator it = stackages.begin(); - it != stackages.end(); - ++it) - { - rospack_tinyxml::TiXmlElement* root = get_manifest_root(*it); - for(rospack_tinyxml::TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_EXPORT); - ele; - ele = ele->NextSiblingElement(MANIFEST_TAG_EXPORT)) - { - for(rospack_tinyxml::TiXmlElement* ele2 = ele->FirstChildElement(name); - ele2; - ele2 = ele2->NextSiblingElement(name)) - { - const char *att_str; - if((att_str = ele2->Attribute(attrib.c_str()))) - { - std::string expanded_str; - if(!expandExportString(*it, att_str, expanded_str)) - return false; - flags.push_back((*it)->name_ + " " + expanded_str); - } - } - } - } - return true; -} - -bool -Rosstackage::depsMsgSrv(const std::string& name, bool direct, - std::vector& gens) -{ - if(!stackages_.count(name)) - { - log_error("librospack", std::string("no such package ") + name); - return false; - } - Stackage* stackage = stackages_[name]; - try - { - computeDeps(stackage); - std::vector deps_vec; - gatherDeps(stackage, direct, POSTORDER, deps_vec); - for(std::vector::const_iterator it = deps_vec.begin(); - it != deps_vec.end(); - ++it) - { - fs::path msg_gen = fs::path((*it)->path_) / - MSG_GEN_GENERATED_DIR / - MSG_GEN_GENERATED_FILE; - fs::path srv_gen = fs::path((*it)->path_) / - SRV_GEN_GENERATED_DIR / - SRV_GEN_GENERATED_FILE; - if(fs::is_regular_file(msg_gen)) - gens.push_back(msg_gen.string()); - if(fs::is_regular_file(srv_gen)) - gens.push_back(srv_gen.string()); - } - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -///////////////////////////////////////////////////////////// -// Rosstackage methods (private) -///////////////////////////////////////////////////////////// -bool -Rosstackage::depsDetail(const std::string& name, bool direct, - std::vector& deps) -{ - if(!stackages_.count(name)) - { - log_error("librospack", std::string("no such package ") + name); - return false; - } - Stackage* stackage = stackages_[name]; - try - { - computeDeps(stackage); - std::vector deps_vec; - gatherDeps(stackage, direct, POSTORDER, deps_vec); - for(std::vector::const_iterator it = deps_vec.begin(); - it != deps_vec.end(); - ++it) - deps.push_back(*it); - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -bool -Rosstackage::dependsOnDetail(const std::string& name, bool direct, - std::vector& deps) -{ - if(!stackages_.count(name)) - log_warn("librospack", std::string("no such package ") + name); - try - { - for(std::tr1::unordered_map::const_iterator it = stackages_.begin(); - it != stackages_.end(); - ++it) - { - computeDeps(it->second, true); - std::vector deps_vec; - gatherDeps(it->second, direct, POSTORDER, deps_vec); - for(std::vector::const_iterator iit = deps_vec.begin(); - iit != deps_vec.end(); - ++iit) - { - if((*iit)->name_ == name) - { - deps.push_back(it->second); - break; - } - } - } - } - catch(Exception& e) - { - log_error("librospack", e.what()); - return false; - } - return true; -} - -bool -Rosstackage::profile(const std::vector& search_path, - bool zombie_only, - int length, - std::vector& dirs) -{ - double start = time_since_epoch(); - std::vector dcrs; - std::tr1::unordered_set dcrs_hash; - for(std::vector::const_iterator p = search_path.begin(); - p != search_path.end(); - ++p) - { - crawlDetail(*p, true, 1, true, dcrs, dcrs_hash); - } - if(!zombie_only) - { - double total = time_since_epoch() - start; - char buf[16]; - snprintf(buf, sizeof(buf), "%.6f", total); - dirs.push_back(std::string("Full tree crawl took ") + buf + " seconds."); - dirs.push_back("Directories marked with (*) contain no manifest. You may"); - dirs.push_back("want to delete these directories."); - dirs.push_back("To get just of list of directories without manifests,"); - dirs.push_back("re-run the profile with --zombie-only"); - dirs.push_back("-------------------------------------------------------------"); - } - std::sort(dcrs.begin(), dcrs.end(), cmpDirectoryCrawlRecord); - std::reverse(dcrs.begin(), dcrs.end()); - int i=0; - for(std::vector::const_iterator it = dcrs.begin(); - it != dcrs.end(); - ++it) - { - if(zombie_only) - { - if((*it)->zombie_) - { - if(length < 0 || i < length) - dirs.push_back((*it)->path_); - i++; - } - } - else - { - char buf[16]; - snprintf(buf, sizeof(buf), "%.6f", (*it)->crawl_time_); - if(length < 0 || i < length) - dirs.push_back(std::string(buf) + " " + - ((*it)->zombie_ ? "* " : " ") + - (*it)->path_); - i++; - } - delete *it; - } - - writeCache(); - return 0; -} - -void -Rosstackage::addStackage(const std::string& path) -{ -#if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2) - std::string name = fs::path(path).filename(); -#else - // in boostfs3, filename() returns a path, which needs to be stringified - std::string name = fs::path(path).filename().string(); -#endif - - if(stackages_.find(name) != stackages_.end()) - { - dups_.insert(name); - return; - } - fs::path manifest_path = fs::path(path) / manifest_name_; - stackages_[name] = new Stackage(name, path, manifest_path.string()); -} - -void -Rosstackage::crawlDetail(const std::string& path, - bool force, - int depth, - bool collect_profile_data, - std::vector& profile_data, - std::tr1::unordered_set& profile_hash) -{ - if(depth > MAX_CRAWL_DEPTH) - throw Exception("maximum depth exceeded during crawl"); - - if(!fs::is_directory(path)) - return; - - if(isStackage(path)) - { - addStackage(path); - return; - } - - fs::path nosubdirs = fs::path(path) / ROSPACK_NOSUBDIRS; - if(fs::is_regular_file(nosubdirs)) - return; - - DirectoryCrawlRecord* dcr = NULL; - if(collect_profile_data) - { - if(profile_hash.find(path) == profile_hash.end()) - { - dcr = new DirectoryCrawlRecord(path, - time_since_epoch(), - stackages_.size()); - profile_data.push_back(dcr); - profile_hash.insert(path); - } - } - - if(crawl_dir_ == CRAWL_DOWN) - { - for(fs::directory_iterator dit = fs::directory_iterator(path); - dit != fs::directory_iterator(); - ++dit) - { - if(fs::is_directory(dit->path())) - { -#if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2) - std::string name = dit->path().filename(); -#else - // in boostfs3, filename() returns a path, which needs to be stringified - std::string name = dit->path().filename().string(); -#endif - // Ignore directories starting with '.' - if(name.size() == 0 || name[0] == '.') - continue; - - crawlDetail(dit->path().string(), force, depth+1, - collect_profile_data, profile_data, profile_hash); - } - } - } - else // dir == CRAWL_UP - { - std::string parent = boost::filesystem::path(path).parent_path().string(); - if(parent.size()) - crawlDetail(parent, force, depth+1, - collect_profile_data, profile_data, profile_hash); - } - - if(collect_profile_data && dcr != NULL) - { - // Measure the elapsed time - dcr->crawl_time_ = time_since_epoch() - dcr->start_time_; - // If the number of packages didn't change while crawling, - // then this directory is a zombie - if(stackages_.size() == dcr->start_num_pkgs_) - dcr->zombie_ = true; - } -} - -void -Rosstackage::loadManifest(Stackage* stackage) -{ - if(stackage->manifest_loaded_) - return; - - if(!stackage->manifest_.LoadFile(stackage->manifest_path_)) - { - std::string errmsg = std::string("error parsing manifest of package ") + - stackage->name_ + " at " + stackage->manifest_path_; - throw Exception(errmsg); - } - stackage->manifest_loaded_ = true; -} - -void -Rosstackage::computeDeps(Stackage* stackage, bool ignore_errors) -{ - if(stackage->deps_computed_) - return; - - stackage->deps_computed_ = true; - - rospack_tinyxml::TiXmlElement* root; - try - { - loadManifest(stackage); - root = get_manifest_root(stackage); - } - catch(Exception& e) - { - if(ignore_errors) - return; - else - throw e; - } - rospack_tinyxml::TiXmlNode *dep_node = NULL; - while((dep_node = root->IterateChildren("depend", dep_node))) - { - rospack_tinyxml::TiXmlElement *dep_ele = dep_node->ToElement(); - const char* dep_pkgname = dep_ele->Attribute(MANIFEST_TAG_PACKAGE); - if(!dep_pkgname) - { - if(!ignore_errors) - { - std::string errmsg = std::string("bad depend syntax (no 'package' attribute) in manifest ") + stackage->name_ + " at " + stackage->manifest_path_; - throw Exception(errmsg); - } - } - else if(dep_pkgname == stackage->name_) - { - if(!ignore_errors) - { - std::string errmsg = std::string("package ") + stackage->name_ + " depends on itself"; - throw Exception(errmsg); - } - } - else if(!stackages_.count(dep_pkgname)) - { - if(ignore_errors) - { - Stackage* dep = new Stackage(dep_pkgname, "", ""); - stackage->deps_.push_back(dep); - } - else - { - std::string errmsg = std::string("package ") + stackage->name_ + " depends on non-existent package " + dep_pkgname; - throw Exception(errmsg); - } - } - else - { - Stackage* dep = stackages_[dep_pkgname]; - stackage->deps_.push_back(dep); - computeDeps(dep, ignore_errors); - } - } -} - -void -Rosstackage::gatherDeps(Stackage* stackage, bool direct, - traversal_order_t order, - std::vector& deps) -{ - std::tr1::unordered_set deps_hash; - std::vector indented_deps; - gatherDepsFull(stackage, direct, order, 0, - deps_hash, deps, false, indented_deps); -} - -// Pre-condition: computeDeps(stackage) succeeded -void -Rosstackage::gatherDepsFull(Stackage* stackage, bool direct, - traversal_order_t order, int depth, - std::tr1::unordered_set& deps_hash, - std::vector& deps, - bool get_indented_deps, - std::vector& indented_deps) -{ - if(depth > MAX_DEPENDENCY_DEPTH) - throw Exception("maximum dependency depth exceeded (likely circular dependency)"); - - for(std::vector::const_iterator it = stackage->deps_.begin(); - it != stackage->deps_.end(); - ++it) - { - bool first = (deps_hash.find(*it) == deps_hash.end()); - if(get_indented_deps || first) - { - if(get_indented_deps) - { - std::string indented_dep; - for(int i=0; iname_); - indented_deps.push_back(indented_dep); - } - - if(first) - { - deps_hash.insert(*it); - // We maintain the vector because the original rospack guaranteed - // ordering in dep reporting. - if(order == PREORDER) - deps.push_back(*it); - if(!direct) - gatherDepsFull(*it, direct, order, depth+1, deps_hash, deps, - get_indented_deps, indented_deps); - if(order == POSTORDER) - deps.push_back(*it); - } - } - } -} - -std::string -Rosstackage::getCachePath() -{ - fs::path cache_path; - - char* ros_home = getenv("ROS_HOME"); - if(ros_home) - cache_path = ros_home; - else - { - // Get the user's home directory by looking up the password entry based - // on UID. If that doesn't work, we fall back on examining $HOME, - // knowing that that can cause trouble when mixed with sudo (#2884). -#if defined(WIN32) - char* home_drive = getenv("HOMEDRIVE"); - char* home_path = getenv("HOMEPATH"); - if(home_drive && home_path) - cache_path = fs::path(home_drive) / fs::path(home_path) / fs::path(DOTROS_NAME); -#else // UNIX - char* home_path; - struct passwd* passwd_ent; - // Look up based on effective UID, just in case we got here by set-uid - if((passwd_ent = getpwuid(geteuid()))) - home_path = passwd_ent->pw_dir; - else - home_path = getenv("HOME"); - if(home_path) - cache_path = fs::path(home_path) / fs::path(DOTROS_NAME); -#endif - } - - // If it doesn't exist, create the directory that will hold the cache - if(!fs::is_directory(cache_path)) - { - try - { - fs::create_directory(cache_path); - } - catch(fs::filesystem_error& e) - { - log_warn("librospack", - std::string("cannot create rospack cache directory ") + - cache_path.string() + ": " + e.what()); - } - } - cache_path /= cache_name_; - return cache_path.string(); -} - -bool -Rosstackage::readCache() -{ - if(!validateCache()) - return false; - - std::string cache_path = getCachePath(); - FILE *cache = fopen(cache_path.c_str(), "r"); - if(cache) - { - char linebuf[30000]; - for(;;) - { - if (!fgets(linebuf, sizeof(linebuf), cache)) - break; // error in read operation - if (linebuf[0] == '#') - continue; - char* newline_pos = strchr(linebuf, '\n'); - if(newline_pos) - *newline_pos = 0; - addStackage(linebuf); - } - fclose(cache); - return true; - } - else - return false; -} - -// TODO: replace the contents of the method with some fancy cross-platform -// boost thing. -void -Rosstackage::writeCache() -{ - // Write the results of this crawl to the cache file. At each step, give - // up on error, printing a warning to stderr. - std::string cache_path = getCachePath(); - if(!cache_path.size()) - { - log_warn("librospack", - "no location available to write cache file. Try setting ROS_HOME or HOME."); - } - else - { - 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(_MSC_VER) - // 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); -#elif defined(__MINGW32__) - char* temp_name = tempnam(dirname(tmp_cache_dir),".rospack_cache."); - snprintf(tmp_cache_path, sizeof(tmp_cache_path), temp_name); - delete temp_name; -#else - snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s/.rospack_cache.XXXXXX", dirname(tmp_cache_dir)); -#endif -#if defined(__MINGW32__) - // There is no equivalent of mkstemp or _mktemp_s on mingw, so we resort to a slightly problematic - // tempnam (above) and mktemp method. This has the miniscule chance of a race condition. - int fd = open(tmp_cache_path, O_RDWR | O_EXCL | _O_CREAT, 0644); - if (fd < 0) - { - log_warn("librospack", - std::string("unable to create temporary cache file ") + - tmp_cache_path, true); - } - else - { - FILE *cache = fdopen(fd, "w"); -#elif defined(WIN32) - 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) - { - fprintf(stderr, "[rospack] Unable to create temporary cache file %s: %s\n", - tmp_cache_path, strerror(errno)); - } - else - { - FILE *cache = fdopen(fd, "w"); -#endif - if (!cache) - { - fprintf(stderr, "[rospack] Unable open cache file %s: %s\n", - tmp_cache_path, strerror(errno)); - } - else - { - // TODO: remove writing of ROS_ROOT - char *rr = getenv("ROS_ROOT"); - fprintf(cache, "#ROS_ROOT=%s\n", rr); - - char *rpp = getenv("ROS_PACKAGE_PATH"); - fprintf(cache, "#ROS_PACKAGE_PATH=%s\n", (rpp ? rpp : "")); - for(std::tr1::unordered_map::const_iterator it = stackages_.begin(); - it != stackages_.end(); - ++it) - fprintf(cache, "%s\n", it->second->path_.c_str()); - fclose(cache); - if(fs::exists(cache_path)) - 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", - tmp_cache_path, cache_path.c_str(), strerror(errno)); - } - } - } - } -} - -bool -Rosstackage::validateCache() -{ - std::string cache_path = getCachePath(); - // first see if it's new enough - double cache_max_age = DEFAULT_MAX_CACHE_AGE; - const char *user_cache_time_str = getenv("ROS_CACHE_TIMEOUT"); - if(user_cache_time_str) - cache_max_age = atof(user_cache_time_str); - if(cache_max_age == 0.0) - return false; - struct stat s; - if(stat(cache_path.c_str(), &s) == 0) - { - double dt = difftime(time(NULL), s.st_mtime); - // Negative cache_max_age means it's always new enough. It's dangerous - // for the user to set this, but rosbash uses it. - if ((cache_max_age > 0.0) && (dt > cache_max_age)) - return false; - } - // try to open it - FILE* cache = fopen(cache_path.c_str(), "r"); - if(!cache) - return false; // it's not readable by us. sad. - - // see if ROS_PACKAGE_PATH matches - char linebuf[30000]; - bool ros_root_ok = false; - bool ros_package_path_ok = false; - // TODO: remove ROS_ROOT - const char* ros_root = getenv("ROS_ROOT"); - const char* ros_package_path = getenv("ROS_PACKAGE_PATH"); - for(;;) - { - if(!fgets(linebuf, sizeof(linebuf), cache)) - break; - linebuf[strlen(linebuf)-1] = 0; // get rid of trailing newline - if (linebuf[0] == '#') - { - if (!strncmp("#ROS_ROOT=", linebuf, 10)) - { - if (!strcmp(linebuf+10, ros_root)) - ros_root_ok = true; - } - else if(!strncmp("#ROS_PACKAGE_PATH=", linebuf, 18)) - { - if(!ros_package_path) - { - if(!strlen(linebuf+18)) - ros_package_path_ok = true; - } - else if(!strcmp(linebuf+18, getenv("ROS_PACKAGE_PATH"))) - ros_package_path_ok = true; - } - } - else - break; // we're out of the header. nothing more matters to this check. - } - fclose(cache); - return ros_root_ok && ros_package_path_ok; -} - -bool -Rosstackage::expandExportString(Stackage* stackage, - const std::string& instring, - std::string& outstring) -{ - outstring = instring; - for(std::string::size_type i = outstring.find(MANIFEST_PREFIX); - i != std::string::npos; - i = outstring.find(MANIFEST_PREFIX)) - { - outstring.replace(i, std::string(MANIFEST_PREFIX).length(), - stackage->path_); - } - - // Do backquote substitution. E.g., if we find this string: - // `pkg-config --cflags gdk-pixbuf-2.0` - // We replace it with the result of executing the command - // contained within the backquotes (reading from its stdout), which - // might be something like: - // -I/usr/include/gtk-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include - - // Construct and execute the string - // We do the assignment first to ensure that if backquote expansion (or - // anything else) fails, we'll get a non-zero exit status from pclose(). - std::string cmd = std::string("ret=\"") + outstring + "\" && echo $ret"; - - // Remove embedded newlines - std::string token("\n"); - for (std::string::size_type s = cmd.find(token); - s != std::string::npos; - s = cmd.find(token, s)) - cmd.replace(s,token.length(),std::string(" ")); - - FILE* p; - if(!(p = popen(cmd.c_str(), "r"))) - { - std::string errmsg = - std::string("failed to execute backquote expression ") + - cmd + " in " + - stackage->manifest_path_; - log_warn("librospack", errmsg, true); - return false; - } - else - { - char buf[8192]; - memset(buf,0,sizeof(buf)); - // Read the command's output - do - { - clearerr(p); - while(fgets(buf + strlen(buf),sizeof(buf)-strlen(buf)-1,p)); - } while(ferror(p) && errno == EINTR); - // Close the subprocess, checking exit status - if(pclose(p) != 0) - { - std::string errmsg = - std::string("got non-zero exit status from executing backquote expression ") + - cmd + " in " + - stackage->manifest_path_; - return false; - } - else - { - // Strip trailing newline, which was added by our call to echo - buf[strlen(buf)-1] = '\0'; - // Replace the backquote expression with the new text - outstring = buf; - } - } - - return true; -} - -///////////////////////////////////////////////////////////// -// Rospack methods -///////////////////////////////////////////////////////////// -Rospack::Rospack(bool quiet) : - Rosstackage(ROSPACK_MANIFEST_NAME, - ROSPACK_CACHE_NAME, - CRAWL_DOWN, - quiet) -{ -} - -Rosstackage::~Rosstackage() -{ - for(std::tr1::unordered_map::const_iterator it = stackages_.begin(); - it != stackages_.end(); - ++it) - { - delete it->second; - } -} - -void -Rospack::crawl(const std::vector& search_path, - bool force) -{ - Rosstackage::crawl(search_path, force); -} - -bool -Rospack::inPackage(std::string& name) -{ - return inStackage(name); -} - -///////////////////////////////////////////////////////////// -// Rosstack methods -///////////////////////////////////////////////////////////// -Rosstack::Rosstack(bool quiet) : - Rosstackage(ROSSTACK_MANIFEST_NAME, - ROSSTACK_CACHE_NAME, - CRAWL_UP, - quiet) -{ -} - -void Rosstack::crawl(const std::vector& search_path, - bool force) -{ - Rosstackage::crawl(search_path, force); -} - -bool -Rosstack::inStack(std::string& name) -{ - return inStackage(name); -} - -rospack_tinyxml::TiXmlElement* -get_manifest_root(Stackage* stackage) -{ - rospack_tinyxml::TiXmlElement* ele = stackage->manifest_.RootElement(); - if(!ele) - { - std::string errmsg = std::string("error parsing manifest of package ") + - stackage->name_ + " at " + stackage->manifest_path_; - throw Exception(errmsg); - } - return ele; -} - -double -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(tmpres) / 1e6; -#else - struct timeval tod; - gettimeofday(&tod, NULL); - return tod.tv_sec + 1e-6 * tod.tv_usec; -#endif -} - - -bool -get_search_path_from_env(std::vector& sp) -{ - char* rr = getenv("ROS_ROOT"); - char* rpp = getenv("ROS_PACKAGE_PATH"); - - if(!rr || !fs::is_directory(rr)) - { - // Test suite checks that we return non-zero on bad ROS_ROOT. This'll - // probably be removed when we get rid of ROS_ROOT. - log_error("librospack", "bad / non-existent ROS_ROOT"); - return false; - } - else - { - sp.push_back(rr); - } - if(rpp) - { - std::vector rpp_strings; - boost::split(rpp_strings, rpp, - boost::is_any_of(":"), - boost::token_compress_on); - for(std::vector::const_iterator it = rpp_strings.begin(); - it != rpp_strings.end(); - ++it) - { - sp.push_back(*it); - } - } - return true; -} - -// Simple console output helpers -void log(const std::string& name, - const std::string& level, - const std::string& msg, - bool append_errno) -{ - if(QUIET) - return; - fprintf(stderr, "[%s] %s: %s", - name.c_str(), level.c_str(), msg.c_str()); - if(append_errno) - fprintf(stderr, ": %s", strerror(errno)); - fprintf(stderr, "\n"); -} - -void log_warn(const std::string& name, - const std::string& msg, - bool append_errno) -{ - log(name, "Warning", msg, append_errno); -} -void log_error(const std::string& name, - const std::string& msg, - bool append_errno) -{ - log(name, "Error", msg, append_errno); -} - -} // namespace rospack diff --git a/tools/rospack/rp.h b/tools/rospack/rp.h deleted file mode 100644 index 34837081..00000000 --- a/tools/rospack/rp.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2008, Willow Garage, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef ROSPACK_ROSPACK_H -#define ROSPACK_ROSPACK_H - -#include -#include -#include -#include -#include -#include - -namespace rospack -{ - -typedef enum -{ - CRAWL_UP, - CRAWL_DOWN -} crawl_direction_t; - -typedef enum -{ - POSTORDER, - PREORDER -} traversal_order_t; - -class Stackage; -class DirectoryCrawlRecord; - -class Rosstackage -{ - private: - std::string manifest_name_; - std::string cache_name_; - crawl_direction_t crawl_dir_; - - bool crawled_; - std::tr1::unordered_set dups_; - void addStackage(const std::string& path); - void crawlDetail(const std::string& path, - bool force, - int depth, - bool collect_profile_data, - std::vector& profile_data, - std::tr1::unordered_set& profile_hash); - bool dependsOnDetail(const std::string& name, bool direct, - std::vector& deps); - bool depsDetail(const std::string& name, bool direct, - std::vector& deps); - bool isStackage(const std::string& path); - void loadManifest(Stackage* stackage); - void computeDeps(Stackage* stackage, bool ignore_errors=false); - void gatherDeps(Stackage* stackage, bool direct, - traversal_order_t order, - std::vector& deps); - void gatherDepsFull(Stackage* stackage, bool direct, - traversal_order_t order, int depth, - std::tr1::unordered_set& deps_hash, - std::vector& deps, - bool get_indented_deps, - std::vector& indented_deps); - std::string getCachePath(); - bool readCache(); - void writeCache(); - bool validateCache(); - bool expandExportString(Stackage* stackage, - const std::string& instring, - std::string& outstring); - - protected: - std::tr1::unordered_map stackages_; - void crawl(const std::vector& search_path, bool force); - bool inStackage(std::string& name); - - public: - Rosstackage(std::string manifest_name, - std::string cache_name, - crawl_direction_t crawl_dir, - bool quiet); - virtual ~Rosstackage(); - - bool find(const std::string& name, std::string& path); - void list(std::vector >& list); - void listDuplicates(std::vector& dups); - bool deps(const std::string& name, bool direct, std::vector& deps); - bool dependsOn(const std::string& name, bool direct, - std::vector& deps); - bool depsManifests(const std::string& name, bool direct, - std::vector& manifests); - bool depsMsgSrv(const std::string& name, bool direct, - std::vector& gens); - bool depsIndent(const std::string& name, bool direct, - std::vector& deps); - bool rosdeps(const std::string& name, bool direct, - std::vector& rosdeps); - bool vcs(const std::string& name, bool direct, - std::vector& vcs); - bool exports(const std::string& name, const std::string& lang, - const std::string& attrib, bool deps_only, - std::vector& flags); - bool plugins(const std::string& name, const std::string& attrib, - const std::string& top, - std::vector& flags); - bool profile(const std::vector& search_path, - bool zombie_only, - int length, - std::vector& dirs); -}; - -class Rospack : public Rosstackage -{ - public: - Rospack(bool quiet=false); - void crawl(const std::vector& search_path, - bool force); - bool inPackage(std::string& name); -}; - -class Rosstack : public Rosstackage -{ - public: - Rosstack(bool quiet=false); - void crawl(const std::vector& search_path, - bool force); - bool inStack(std::string& name); -}; - -bool get_search_path_from_env(std::vector& sp); - -// Simple console output helpers -void log_warn(const std::string& name, - const std::string& msg, - bool append_errno = false); -void log_error(const std::string& name, - const std::string& msg, - bool append_errno = false); - -} // namespace rospack - - -#endif diff --git a/tools/rospack/rp_main.cpp b/tools/rospack/rp_main.cpp deleted file mode 100644 index 2bf30e64..00000000 --- a/tools/rospack/rp_main.cpp +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright (C) 2008, Willow Garage, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "rp.h" -#include -#include -#include -#include -#include -#include - -namespace po = boost::program_options; - -const char* usage(); -bool parse_args(int argc, char** argv, po::variables_map& vm); -void parse_compiler_flags(const std::string& instring, - const std::string& token, - bool select, - bool last, - std::string& outstring); -void deduplicate_tokens(const std::string& instring, - bool last, - std::string& outstring); - -int -main(int argc, char** argv) -{ - po::variables_map vm; - - if(!parse_args(argc, argv, vm)) - return 1; - - bool quiet = (vm.count("quiet")==1); - rospack::Rospack rp(quiet); - - std::string command; - std::string package; - bool package_given = false; - bool deps_only = false; - std::string lang; - std::string attrib; - std::string top; - std::string target; - bool zombie_only = false; - std::string length_str; - int length; - if(vm.count("command")) - command = vm["command"].as(); - if(!command.size()) - { - rospack::log_error("rospack", "no command given. Try 'rospack help'"); - return 0; - } - // For some commands, we force a crawl. Definitely anything that does a - // depends-on calculation. - bool force = false; - if((command == "profile") || - (command == "depends-on") || - (command == "depends-on1") || - (command == "langs") || - (command == "list-duplicates")) - force = true; - std::vector search_path; - if(!rospack::get_search_path_from_env(search_path)) - return 1; - - if(vm.count("package")) - { - package = vm["package"].as(); - package_given = true; - } - else - { - // try to determine package from directory context - rp.inPackage(package); - } - if(vm.count("deps-only")) - deps_only = true; - if(vm.count("lang")) - lang = vm["lang"].as(); - if(vm.count("attrib")) - attrib = vm["attrib"].as(); - if(vm.count("top")) - top = vm["top"].as(); - if(vm.count("target")) - target = vm["target"].as(); - if(vm.count("zombie-only")) - zombie_only = true; - if(vm.count("length")) - { - length_str = vm["length"].as(); - length = atoi(length_str.c_str()); - } - else - { - if(zombie_only) - length = -1; - else - length = 20; - } - - // COMMAND: profile - if(command == "profile") - { - if(package_given || target.size() || top.size() || - deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector dirs; - if(rp.profile(search_path, zombie_only, length, dirs)) - return 1; - for(std::vector::const_iterator it = dirs.begin(); - it != dirs.end(); - ++it) - printf("%s\n", (*it).c_str()); - return 0; - } - - // We crawl here because profile (above) does its own special crawl. - rp.crawl(search_path, force); - - // COMMAND: find [package] - if(command == "find") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::string path; - if(!rp.find(package, path)) - return 1; - printf("%s\n", path.c_str()); - return 0; - } - // COMMAND: list - else if(command == "list") - { - if(package_given || target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector > list; - rp.list(list); - for(std::vector >::const_iterator it = list.begin(); - it != list.end(); - ++it) - { - printf("%s %s\n", it->first.c_str(), it->second.c_str()); - } - return 0; - } - // COMMAND: list-names - else if(command == "list-names") - { - if(package_given || target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector > list; - rp.list(list); - for(std::vector >::const_iterator it = list.begin(); - it != list.end(); - ++it) - { - printf("%s\n", it->first.c_str()); - } - return 0; - } - // COMMAND: list-duplicates - else if(command == "list-duplicates") - { - if(package_given || target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector dups; - rp.listDuplicates(dups); - // list-duplicates returns 0 if no duplicates - if(!dups.size()) - return 0; - // if there are dups, list-duplicates prints them and returns non-zero - for(std::vector::const_iterator it = dups.begin(); - it != dups.end(); - ++it) - { - printf("%s\n", (*it).c_str()); - } - return 1; - } - // COMMAND: langs - else if(command == "langs") - { - if(package_given || target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector deps; - if(!rp.dependsOn("roslang", true, deps)) - return 1; - const char* ros_lang_disable; - if((ros_lang_disable = getenv("ROS_LANG_DISABLE"))) - { - std::vector disable_langs; - boost::split(disable_langs, ros_lang_disable, - boost::is_any_of(":"), - boost::token_compress_on); - std::vector::iterator it = deps.begin(); - while(it != deps.end()) - { - if(std::find(disable_langs.begin(), disable_langs.end(), *it) != - disable_langs.end()) - it = deps.erase(it); - else - ++it; - } - } - for(std::vector::const_iterator it = deps.begin(); - it != deps.end(); - ++it) - printf("%s ", it->c_str()); - printf("\n"); - return 0; - } - // COMMAND: depends [package] (alias: deps) - else if(command == "depends" || command == "deps" || - command == "depends1" || command == "deps1") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector deps; - if(!rp.deps(package, (command == "depends1" || command == "deps1"), deps)) - return 1; - for(std::vector::const_iterator it = deps.begin(); - it != deps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } - // COMMAND: depends-manifests [package] (alias: deps-manifests) - else if(command == "depends-manifests" || command == "deps-manifests") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector manifests; - if(!rp.depsManifests(package, false, manifests)) - return 1; - for(std::vector::const_iterator it = manifests.begin(); - it != manifests.end(); - ++it) - printf("%s ", it->c_str()); - printf("\n"); - return 0; - } - // COMMAND: depends-msgsrv [package] (alias: deps-msgsrv) - else if(command == "depends-msgsrv" || command == "deps-msgsrv") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector gens; - if(!rp.depsMsgSrv(package, false, gens)) - return 1; - for(std::vector::const_iterator it = gens.begin(); - it != gens.end(); - ++it) - printf("%s ", it->c_str()); - printf("\n"); - return 0; - } - // COMMAND: depends-indent [package] (alias: deps-indent) - else if(command == "depends-indent" || command == "deps-indent") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector deps; - if(!rp.depsIndent(package, false, deps)) - return 1; - for(std::vector::const_iterator it = deps.begin(); - it != deps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } - // COMMAND: rosdep [package] (alias: rosdeps) - // COMMAND: rosdep0 [package] (alias: rosdeps0) - else if(command == "rosdep" || command == "rosdeps" || - command == "rosdep0" || command == "rosdeps0") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector rosdeps; - if(!rp.rosdeps(package, (command == "rosdep0" || command == "rosdeps0"), rosdeps)) - return 1; - for(std::vector::const_iterator it = rosdeps.begin(); - it != rosdeps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } - // COMMAND: vcs [package] - // COMMAND: vcs0 [package] - else if(command == "vcs" || command == "vcs0") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector vcs; - if(!rp.vcs(package, (command == "vcs0"), vcs)) - return 1; - for(std::vector::const_iterator it = vcs.begin(); - it != vcs.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } - // COMMAND: depends-on [package] - // COMMAND: depends-on1 [package] - else if(command == "depends-on" || command == "depends-on1") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector deps; - if(!rp.dependsOn(package, (command == "depends-on1"), deps)) - return 1; - for(std::vector::const_iterator it = deps.begin(); - it != deps.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } - // COMMAND: export [--deps-only] --lang= --attrib= [package] - else if(command == "export") - { - if(!package.size() || !lang.size() || !attrib.size()) - { - rospack::log_error("rospack", "no package / lang / attrib given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || zombie_only) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector flags; - if(!rp.exports(package, lang, attrib, deps_only, flags)) - return 1; - for(std::vector::const_iterator it = flags.begin(); - it != flags.end(); - ++it) - printf("%s ", it->c_str()); - printf("\n"); - return 0; - } - // COMMAND: plugins --attrib= [--top=] [package] - else if(command == "plugins") - { - if(!package.size() || !attrib.size()) - { - rospack::log_error("rospack", "no package / attrib given"); - return 1; - } - if(target.size() || length_str.size() || zombie_only) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector flags; - if(!rp.plugins(package, attrib, top, flags)) - return 1; - for(std::vector::const_iterator it = flags.begin(); - it != flags.end(); - ++it) - printf("%s\n", it->c_str()); - return 0; - } - // COMMAND: cflags-only-I [--deps-only] [package] - else if(command == "cflags-only-I") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || zombie_only) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector flags; - if(!rp.exports(package, "cpp", "cflags", deps_only, flags)) - return 1; - std::string combined; - for(std::vector::const_iterator it = flags.begin(); - it != flags.end(); - ++it) - combined.append(*it + " "); - std::string result; - parse_compiler_flags(combined, "-I", true, false, result); - printf("%s\n", result.c_str()); - return 0; - } - // COMMAND: cflags-only-other [--deps-only] [package] - else if(command == "cflags-only-other") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || zombie_only) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector flags; - if(!rp.exports(package, "cpp", "cflags", deps_only, flags)) - return 1; - std::string combined; - for(std::vector::const_iterator it = flags.begin(); - it != flags.end(); - ++it) - combined.append(*it + " "); - std::string result; - parse_compiler_flags(combined, "-I", false, false, result); - printf("%s\n", result.c_str()); - return 0; - } - // COMMAND: libs-only-L [--deps-only] [package] - else if(command == "libs-only-L") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || zombie_only) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector flags; - if(!rp.exports(package, "cpp", "lflags", deps_only, flags)) - return 1; - std::string combined; - for(std::vector::const_iterator it = flags.begin(); - it != flags.end(); - ++it) - combined.append(*it + " "); - std::string result; - parse_compiler_flags(combined, "-L", true, false, result); - printf("%s\n", result.c_str()); - return 0; - } - // COMMAND: libs-only-l [--deps-only] [package] - else if(command == "libs-only-l") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || zombie_only) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector flags; - if(!rp.exports(package, "cpp", "lflags", deps_only, flags)) - return 1; - std::string combined; - for(std::vector::const_iterator it = flags.begin(); - it != flags.end(); - ++it) - combined.append(*it + " "); - std::string result; - parse_compiler_flags(combined, "-l", true, true, result); - printf("%s\n", result.c_str()); - return 0; - } - // COMMAND: libs-only-other [--deps-only] [package] - else if(command == "libs-only-other") - { - if(!package.size()) - { - rospack::log_error("rospack", "no package given"); - return 1; - } - if(target.size() || top.size() || length_str.size() || zombie_only) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - std::vector flags; - if(!rp.exports(package, "cpp", "lflags", deps_only, flags)) - return 1; - std::string combined; - for(std::vector::const_iterator it = flags.begin(); - it != flags.end(); - ++it) - combined.append(*it + " "); - std::string intermediate; - parse_compiler_flags(combined, "-L", false, false, intermediate); - std::string result; - parse_compiler_flags(intermediate, "-l", false, false, result); - printf("%s\n", result.c_str()); - return 0; - } - // COMMAND: help - else if(command == "help") - { - if(package_given || top.size() || length_str.size() || - zombie_only || deps_only || lang.size() || attrib.size()) - { - rospack::log_error("rospack", "invalid option(s) given"); - return 1; - } - printf("%s", usage()); - return 0; - } - else - { - rospack::log_error("rospack", - std::string("command ") + command + " not implemented"); - return 1; - } -} - -void -deduplicate_tokens(const std::string& instring, - bool last, - std::string& outstring) -{ - std::vector vec; - std::tr1::unordered_set set; - boost::split(vec, instring, - boost::is_any_of("\t "), - boost::token_compress_on); - if(last) - std::reverse(vec.begin(), vec.end()); - std::vector vec_out; - vec_out.resize(vec.size()); - int i = 0; - for(std::vector::const_iterator it = vec.begin(); - it != vec.end(); - ++it) - { - if(set.find(*it) == set.end()) - { - vec_out[i] = *it; - set.insert(*it); - i++; - } - } - if(last) - std::reverse(vec_out.begin(), vec_out.end()); - for(std::vector::const_iterator it = vec_out.begin(); - it != vec_out.end(); - ++it) - outstring.append(*it + " "); -} - -void -parse_compiler_flags(const std::string& instring, - const std::string& token, - bool select, - bool last, - std::string& outstring) -{ - std::string intermediate; - std::vector result_vec; - boost::split(result_vec, instring, - boost::is_any_of("\t "), - boost::token_compress_on); - for(std::vector::const_iterator it = result_vec.begin(); - it != result_vec.end(); - ++it) - { - // Combined into one arg - if(it->size() > token.size() && it->substr(0,token.size()) == token) - { - if(select) - intermediate.append(it->substr(token.size()) + " "); - } - // Space-separated - else if((*it) == token) - { - std::vector::const_iterator iit = it; - if(++iit != result_vec.end()) - { - if(it->size() >= token.size() && it->substr(0,token.size()) == token) - { - // skip it - } - else - { - if(select) - intermediate.append((*iit) + " "); - it = iit; - } - } - } - // Special case: if we're told to look for -l, then also find *.a - else if(it->size() > 2 && - (*it)[0] == '/' && - it->substr(it->size()-2) == ".a") - { - if(select) - intermediate.append((*it) + " "); - } - else if(!select) - intermediate.append((*it) + " "); - } - deduplicate_tokens(intermediate, last, outstring); -} - -const char* usage() -{ - return "USAGE: rospack [options] [package]\n" - " Allowed commands:\n" - " help\n" - " find [package]\n" - " list\n" - " list-names\n" - " list-duplicates\n" - " langs\n" - " depends [package] (alias: deps)\n" - " depends-manifests [package] (alias: deps-manifests)\n" - " depends-msgsrv [package] (alias: deps-msgsrv)\n" - " depends1 [package] (alias: deps1)\n" - " depends-indent [package] (alias: deps-indent)\n" - " depends-why --target= [package] (alias: deps-why)\n" - " rosdep [package] (alias: rosdeps)\n" - " rosdep0 [package] (alias: rosdeps0)\n" - " vcs [package]\n" - " vcs0 [package]\n" - " depends-on [package]\n" - " depends-on1 [package]\n" - " export [--deps-only] --lang= --attrib= [package]\n" - " plugins --attrib= [--top=] [package]\n" - " cflags-only-I [--deps-only] [package]\n" - " cflags-only-other [--deps-only] [package]\n" - " libs-only-L [--deps-only] [package]\n" - " libs-only-l [--deps-only] [package]\n" - " libs-only-other [--deps-only] [package]\n" - " profile [--length=] [--zombie-only]\n" - " Extra options:\n" - " -q Quiets error reports.\n\n" - " If [package] is omitted, the current working directory\n" - " is used (if it contains a manifest.xml).\n\n"; -} - -bool -parse_args(int argc, char** argv, po::variables_map& vm) -{ - po::options_description desc("Allowed options"); - desc.add_options() - ("command", po::value(), "command") - ("package", po::value(), "package") - ("target", po::value(), "target") - ("deps-only", "deps-only") - ("lang", po::value(), "lang") - ("attrib", po::value(), "attrib") - ("top", po::value(), "top") - ("length", po::value(), "length") - ("zombie-only", "zombie-only") - ("quiet,q", "quiet"); - - po::positional_options_description pd; - pd.add("command", 1).add("package", 1); - try - { - po::store(po::command_line_parser(argc, argv).options(desc).positional(pd).run(), vm); - } - catch(boost::program_options::error e) - { - rospack::log_error("rospack", std::string("failed to parse command-line options: ") + e.what()); - return false; - } - po::notify(vm); - - return true; -} - diff --git a/tools/rospack/rs_main.cpp b/tools/rospack/rs_main.cpp deleted file mode 100644 index 4e5f6d35..00000000 --- a/tools/rospack/rs_main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2008, Willow Garage, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "rp.h" -#include - -int -main(int argc, char** argv) -{ - rospack::Rosstack rs; - - std::vector search_path; - search_path.push_back("/Users/gerkey/code/ros/ros"); - search_path.push_back("/Users/gerkey/code/ros/ros/tools/rospack"); - search_path.push_back("/Users/gerkey/code/ros/ros_comm"); - rs.crawl(search_path, false); - - return 0; -} diff --git a/tools/rospack/tinyxml-2.5.3/readme.txt b/tools/rospack/tinyxml-2.5.3/readme.txt deleted file mode 100644 index 14ec3d2e..00000000 --- a/tools/rospack/tinyxml-2.5.3/readme.txt +++ /dev/null @@ -1,530 +0,0 @@ -/** @mainpage - -

TinyXML

- -TinyXML is a simple, small, C++ XML parser that can be easily -integrated into other programs. - -

What it does.

- -In brief, TinyXML parses an XML document, and builds from that a -Document Object Model (DOM) that can be read, modified, and saved. - -XML stands for "eXtensible Markup Language." It allows you to create -your own document markups. Where HTML does a very good job of marking -documents for browsers, XML allows you to define any kind of document -markup, for example a document that describes a "to do" list for an -organizer application. XML is a very structured and convenient format. -All those random file formats created to store application data can -all be replaced with XML. One parser for everything. - -The best place for the complete, correct, and quite frankly hard to -read spec is at -http://www.w3.org/TR/2004/REC-xml-20040204/. An intro to XML -(that I really like) can be found at -http://skew.org/xml/tutorial. - -There are different ways to access and interact with XML data. -TinyXML uses a Document Object Model (DOM), meaning the XML data is parsed -into a C++ objects that can be browsed and manipulated, and then -written to disk or another output stream. You can also construct an XML document -from scratch with C++ objects and write this to disk or another output -stream. - -TinyXML is designed to be easy and fast to learn. It is two headers -and four cpp files. Simply add these to your project and off you go. -There is an example file - xmltest.cpp - to get you started. - -TinyXML is released under the ZLib license, -so you can use it in open source or commercial code. The details -of the license are at the top of every source file. - -TinyXML attempts to be a flexible parser, but with truly correct and -compliant XML output. TinyXML should compile on any reasonably C++ -compliant system. It does not rely on exceptions or RTTI. It can be -compiled with or without STL support. TinyXML fully supports -the UTF-8 encoding, and the first 64k character entities. - - -

What it doesn't do.

- -TinyXML doesn't parse or use DTDs (Document Type Definitions) or XSLs -(eXtensible Stylesheet Language.) There are other parsers out there -(check out www.sourceforge.org, search for XML) that are much more fully -featured. But they are also much bigger, take longer to set up in -your project, have a higher learning curve, and often have a more -restrictive license. If you are working with browsers or have more -complete XML needs, TinyXML is not the parser for you. - -The following DTD syntax will not parse at this time in TinyXML: - -@verbatim - - ]> -@endverbatim - -because TinyXML sees this as a !DOCTYPE node with an illegally -embedded !ELEMENT node. This may be addressed in the future. - -

Tutorials.

- -For the impatient, here is a tutorial to get you going. A great way to get started, -but it is worth your time to read this (very short) manual completely. - -- @subpage tutorial0 - -

Code Status.

- -TinyXML is mature, tested code. It is very stable. If you find -bugs, please file a bug report on the sourceforge web site -(www.sourceforge.net/projects/tinyxml). We'll get them straightened -out as soon as possible. - -There are some areas of improvement; please check sourceforge if you are -interested in working on TinyXML. - -

Related Projects

- -TinyXML projects you may find useful! (Descriptions provided by the projects.) - -
    -
  • TinyXPath (http://tinyxpath.sourceforge.net). TinyXPath is a small footprint - XPath syntax decoder, written in C++.
  • -
  • TinyXML++ (http://code.google.com/p/ticpp/). TinyXML++ is a completely new - interface to TinyXML that uses MANY of the C++ strengths. Templates, - exceptions, and much better error handling.
  • -
- -

Features

- -

Using STL

- -TinyXML can be compiled to use or not use STL. When using STL, TinyXML -uses the std::string class, and fully supports std::istream, std::ostream, -operator<<, and operator>>. Many API methods have both 'const char*' and -'const std::string&' forms. - -When STL support is compiled out, no STL files are included whatsoever. All -the string classes are implemented by TinyXML itself. API methods -all use the 'const char*' form for input. - -Use the compile time #define: - - TIXML_USE_STL - -to compile one version or the other. This can be passed by the compiler, -or set as the first line of "tinyxml.h". - -Note: If compiling the test code in Linux, setting the environment -variable TINYXML_USE_STL=YES/NO will control STL compilation. In the -Windows project file, STL and non STL targets are provided. In your project, -It's probably easiest to add the line "#define TIXML_USE_STL" as the first -line of tinyxml.h. - -

UTF-8

- -TinyXML supports UTF-8 allowing to manipulate XML files in any language. TinyXML -also supports "legacy mode" - the encoding used before UTF-8 support and -probably best described as "extended ascii". - -Normally, TinyXML will try to detect the correct encoding and use it. However, -by setting the value of TIXML_DEFAULT_ENCODING in the header file, TinyXML -can be forced to always use one encoding. - -TinyXML will assume Legacy Mode until one of the following occurs: -
    -
  1. If the non-standard but common "UTF-8 lead bytes" (0xef 0xbb 0xbf) - begin the file or data stream, TinyXML will read it as UTF-8.
  2. -
  3. If the declaration tag is read, and it has an encoding="UTF-8", then - TinyXML will read it as UTF-8.
  4. -
  5. If the declaration tag is read, and it has no encoding specified, then TinyXML will - read it as UTF-8.
  6. -
  7. If the declaration tag is read, and it has an encoding="something else", then TinyXML - will read it as Legacy Mode. In legacy mode, TinyXML will work as it did before. It's - not clear what that mode does exactly, but old content should keep working.
  8. -
  9. Until one of the above criteria is met, TinyXML runs in Legacy Mode.
  10. -
- -What happens if the encoding is incorrectly set or detected? TinyXML will try -to read and pass through text seen as improperly encoded. You may get some strange results or -mangled characters. You may want to force TinyXML to the correct mode. - -You may force TinyXML to Legacy Mode by using LoadFile( TIXML_ENCODING_LEGACY ) or -LoadFile( filename, TIXML_ENCODING_LEGACY ). You may force it to use legacy mode all -the time by setting TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY. Likewise, you may -force it to TIXML_ENCODING_UTF8 with the same technique. - -For English users, using English XML, UTF-8 is the same as low-ASCII. You -don't need to be aware of UTF-8 or change your code in any way. You can think -of UTF-8 as a "superset" of ASCII. - -UTF-8 is not a double byte format - but it is a standard encoding of Unicode! -TinyXML does not use or directly support wchar, TCHAR, or Microsoft's _UNICODE at this time. -It is common to see the term "Unicode" improperly refer to UTF-16, a wide byte encoding -of unicode. This is a source of confusion. - -For "high-ascii" languages - everything not English, pretty much - TinyXML can -handle all languages, at the same time, as long as the XML is encoded -in UTF-8. That can be a little tricky, older programs and operating systems -tend to use the "default" or "traditional" code page. Many apps (and almost all -modern ones) can output UTF-8, but older or stubborn (or just broken) ones -still output text in the default code page. - -For example, Japanese systems traditionally use SHIFT-JIS encoding. -Text encoded as SHIFT-JIS can not be read by TinyXML. -A good text editor can import SHIFT-JIS and then save as UTF-8. - -The Skew.org link does a great -job covering the encoding issue. - -The test file "utf8test.xml" is an XML containing English, Spanish, Russian, -and Simplified Chinese. (Hopefully they are translated correctly). The file -"utf8test.gif" is a screen capture of the XML file, rendered in IE. Note that -if you don't have the correct fonts (Simplified Chinese or Russian) on your -system, you won't see output that matches the GIF file even if you can parse -it correctly. Also note that (at least on my Windows machine) console output -is in a Western code page, so that Print() or printf() cannot correctly display -the file. This is not a bug in TinyXML - just an OS issue. No data is lost or -destroyed by TinyXML. The console just doesn't render UTF-8. - - -

Entities

-TinyXML recognizes the pre-defined "character entities", meaning special -characters. Namely: - -@verbatim - & & - < < - > > - " " - ' ' -@endverbatim - -These are recognized when the XML document is read, and translated to there -UTF-8 equivalents. For instance, text with the XML of: - -@verbatim - Far & Away -@endverbatim - -will have the Value() of "Far & Away" when queried from the TiXmlText object, -and will be written back to the XML stream/file as an ampersand. Older versions -of TinyXML "preserved" character entities, but the newer versions will translate -them into characters. - -Additionally, any character can be specified by its Unicode code point: -The syntax " " or " " are both to the non-breaking space characher. - -

Printing

-TinyXML can print output in several different ways that all have strengths and limitations. - -- Print( FILE* ). Output to a std-C stream, which includes all C files as well as stdout. - - "Pretty prints", but you don't have control over printing options. - - The output is streamed directly to the FILE object, so there is no memory overhead - in the TinyXML code. - - used by Print() and SaveFile() - -- operator<<. Output to a c++ stream. - - Integrates with standart C++ iostreams. - - Outputs in "network printing" mode without line breaks. Good for network transmission - and moving XML between C++ objects, but hard for a human to read. - -- TiXmlPrinter. Output to a std::string or memory buffer. - - API is less concise - - Future printing options will be put here. - - Printing may change slightly in future versions as it is refined and expanded. - -

Streams

-With TIXML_USE_STL on TinyXML supports C++ streams (operator <<,>>) streams as well -as C (FILE*) streams. There are some differences that you may need to be aware of. - -C style output: - - based on FILE* - - the Print() and SaveFile() methods - - Generates formatted output, with plenty of white space, intended to be as - human-readable as possible. They are very fast, and tolerant of ill formed - XML documents. For example, an XML document that contains 2 root elements - and 2 declarations, will still print. - -C style input: - - based on FILE* - - the Parse() and LoadFile() methods - - A fast, tolerant read. Use whenever you don't need the C++ streams. - -C++ style output: - - based on std::ostream - - operator<< - - Generates condensed output, intended for network transmission rather than - readability. Depending on your system's implementation of the ostream class, - these may be somewhat slower. (Or may not.) Not tolerant of ill formed XML: - a document should contain the correct one root element. Additional root level - elements will not be streamed out. - -C++ style input: - - based on std::istream - - operator>> - - Reads XML from a stream, making it useful for network transmission. The tricky - part is knowing when the XML document is complete, since there will almost - certainly be other data in the stream. TinyXML will assume the XML data is - complete after it reads the root element. Put another way, documents that - are ill-constructed with more than one root element will not read correctly. - Also note that operator>> is somewhat slower than Parse, due to both - implementation of the STL and limitations of TinyXML. - -

White space

-The world simply does not agree on whether white space should be kept, or condensed. -For example, pretend the '_' is a space, and look at "Hello____world". HTML, and -at least some XML parsers, will interpret this as "Hello_world". They condense white -space. Some XML parsers do not, and will leave it as "Hello____world". (Remember -to keep pretending the _ is a space.) Others suggest that __Hello___world__ should become -Hello___world. - -It's an issue that hasn't been resolved to my satisfaction. TinyXML supports the -first 2 approaches. Call TiXmlBase::SetCondenseWhiteSpace( bool ) to set the desired behavior. -The default is to condense white space. - -If you change the default, you should call TiXmlBase::SetCondenseWhiteSpace( bool ) -before making any calls to Parse XML data, and I don't recommend changing it after -it has been set. - - -

Handles

- -Where browsing an XML document in a robust way, it is important to check -for null returns from method calls. An error safe implementation can -generate a lot of code like: - -@verbatim -TiXmlElement* root = document.FirstChildElement( "Document" ); -if ( root ) -{ - TiXmlElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - TiXmlElement* child = element->FirstChildElement( "Child" ); - if ( child ) - { - TiXmlElement* child2 = child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. -@endverbatim - -Handles have been introduced to clean this up. Using the TiXmlHandle class, -the previous code reduces to: - -@verbatim -TiXmlHandle docHandle( &document ); -TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); -if ( child2 ) -{ - // do something useful -@endverbatim - -Which is much easier to deal with. See TiXmlHandle for more information. - - -

Row and Column tracking

-Being able to track nodes and attributes back to their origin location -in source files can be very important for some applications. Additionally, -knowing where parsing errors occured in the original source can be very -time saving. - -TinyXML can tracks the row and column origin of all nodes and attributes -in a text file. The TiXmlBase::Row() and TiXmlBase::Column() methods return -the origin of the node in the source text. The correct tabs can be -configured in TiXmlDocument::SetTabSize(). - - -

Using and Installing

- -To Compile and Run xmltest: - -A Linux Makefile and a Windows Visual C++ .dsw file is provided. -Simply compile and run. It will write the file demotest.xml to your -disk and generate output on the screen. It also tests walking the -DOM by printing out the number of nodes found using different -techniques. - -The Linux makefile is very generic and runs on many systems - it -is currently tested on mingw and -MacOSX. You do not need to run 'make depend'. The dependecies have been -hard coded. - -

Windows project file for VC6

-
    -
  • tinyxml: tinyxml library, non-STL
  • -
  • tinyxmlSTL: tinyxml library, STL
  • -
  • tinyXmlTest: test app, non-STL
  • -
  • tinyXmlTestSTL: test app, STL
  • -
- -

Makefile

-At the top of the makefile you can set: - -PROFILE, DEBUG, and TINYXML_USE_STL. Details (such that they are) are in -the makefile. - -In the tinyxml directory, type "make clean" then "make". The executable -file 'xmltest' will be created. - - - -

To Use in an Application:

- -Add tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp, and tinystr.h to your -project or make file. That's it! It should compile on any reasonably -compliant C++ system. You do not need to enable exceptions or -RTTI for TinyXML. - - -

How TinyXML works.

- -An example is probably the best way to go. Take: -@verbatim - - - - Go to the Toy store! - Do bills - -@endverbatim - -Its not much of a To Do list, but it will do. To read this file -(say "demo.xml") you would create a document, and parse it in: -@verbatim - TiXmlDocument doc( "demo.xml" ); - doc.LoadFile(); -@endverbatim - -And its ready to go. Now lets look at some lines and how they -relate to the DOM. - -@verbatim - -@endverbatim - - The first line is a declaration, and gets turned into the - TiXmlDeclaration class. It will be the first child of the - document node. - - This is the only directive/special tag parsed by by TinyXML. - Generally directive tags are stored in TiXmlUnknown so the - commands wont be lost when it is saved back to disk. - -@verbatim - -@endverbatim - - A comment. Will become a TiXmlComment object. - -@verbatim - -@endverbatim - - The "ToDo" tag defines a TiXmlElement object. This one does not have - any attributes, but does contain 2 other elements. - -@verbatim - -@endverbatim - - Creates another TiXmlElement which is a child of the "ToDo" element. - This element has 1 attribute, with the name "priority" and the value - "1". - -@verbatim -Go to the -@endverbatim - - A TiXmlText. This is a leaf node and cannot contain other nodes. - It is a child of the "Item" TiXmlElement. - -@verbatim - -@endverbatim - - - Another TiXmlElement, this one a child of the "Item" element. - -Etc. - -Looking at the entire object tree, you end up with: -@verbatim -TiXmlDocument "demo.xml" - TiXmlDeclaration "version='1.0'" "standalone=no" - TiXmlComment " Our to do list data" - TiXmlElement "ToDo" - TiXmlElement "Item" Attribtutes: priority = 1 - TiXmlText "Go to the " - TiXmlElement "bold" - TiXmlText "Toy store!" - TiXmlElement "Item" Attributes: priority=2 - TiXmlText "Do bills" -@endverbatim - -

Documentation

- -The documentation is build with Doxygen, using the 'dox' -configuration file. - -

License

- -TinyXML is released under the zlib license: - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. - -

References

- -The World Wide Web Consortium is the definitive standard body for -XML, and there web pages contain huge amounts of information. - -The definitive spec: -http://www.w3.org/TR/2004/REC-xml-20040204/ - -I also recommend "XML Pocket Reference" by Robert Eckstein and published by -OReilly...the book that got the whole thing started. - -

Contributors, Contacts, and a Brief History

- -Thanks very much to everyone who sends suggestions, bugs, ideas, and -encouragement. It all helps, and makes this project fun. A special thanks -to the contributors on the web pages that keep it lively. - -So many people have sent in bugs and ideas, that rather than list here -we try to give credit due in the "changes.txt" file. - -TinyXML was originally written by Lee Thomason. (Often the "I" still -in the documentation.) Lee reviews changes and releases new versions, -with the help of Yves Berquin, Andrew Ellerton, and the tinyXml community. - -We appreciate your suggestions, and would love to know if you -use TinyXML. Hopefully you will enjoy it and find it useful. -Please post questions, comments, file bugs, or contact us at: - -www.sourceforge.net/projects/tinyxml - -Lee Thomason, Yves Berquin, Andrew Ellerton -*/ diff --git a/tools/rospack/tinyxml-2.5.3/tinystr.cpp b/tools/rospack/tinyxml-2.5.3/tinystr.cpp deleted file mode 100644 index d847c88e..00000000 --- a/tools/rospack/tinyxml-2.5.3/tinystr.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -/* - * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005. - */ - - -#ifndef TIXML_USE_STL - -#include "tinystr.h" - -namespace rospack_tinyxml { - -// Error value for find primitive -const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); - - -// Null rep. -TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; - - -void TiXmlString::reserve (size_type cap) -{ - if (cap > capacity()) - { - TiXmlString tmp; - tmp.init(length(), cap); - memcpy(tmp.start(), data(), length()); - swap(tmp); - } -} - - -TiXmlString& TiXmlString::assign(const char* str, size_type len) -{ - size_type cap = capacity(); - if (len > cap || cap > 3*(len + 8)) - { - TiXmlString tmp; - tmp.init(len); - memcpy(tmp.start(), str, len); - swap(tmp); - } - else - { - memmove(start(), str, len); - set_size(len); - } - return *this; -} - - -TiXmlString& TiXmlString::append(const char* str, size_type len) -{ - size_type newsize = length() + len; - if (newsize > capacity()) - { - reserve (newsize + capacity()); - } - memmove(finish(), str, len); - set_size(newsize); - return *this; -} - - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) -{ - TiXmlString tmp; - tmp.reserve(a.length() + b.length()); - tmp += a; - tmp += b; - return tmp; -} - -TiXmlString operator + (const TiXmlString & a, const char* b) -{ - TiXmlString tmp; - TiXmlString::size_type b_len = static_cast( strlen(b) ); - tmp.reserve(a.length() + b_len); - tmp += a; - tmp.append(b, b_len); - return tmp; -} - -TiXmlString operator + (const char* a, const TiXmlString & b) -{ - TiXmlString tmp; - TiXmlString::size_type a_len = static_cast( strlen(a) ); - tmp.reserve(a_len + b.length()); - tmp.append(a, a_len); - tmp += b; - return tmp; -} - -} -#endif // TIXML_USE_STL diff --git a/tools/rospack/tinyxml-2.5.3/tinystr.h b/tools/rospack/tinyxml-2.5.3/tinystr.h deleted file mode 100644 index 19ca832c..00000000 --- a/tools/rospack/tinyxml-2.5.3/tinystr.h +++ /dev/null @@ -1,322 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -/* - * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. - * - * - completely rewritten. compact, clean, and fast implementation. - * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) - * - fixed reserve() to work as per specification. - * - fixed buggy compares operator==(), operator<(), and operator>() - * - fixed operator+=() to take a const ref argument, following spec. - * - added "copy" constructor with length, and most compare operators. - * - added swap(), clear(), size(), capacity(), operator+(). - */ - -#ifndef TIXML_USE_STL - -#ifndef TIXML_STRING_INCLUDED -#define TIXML_STRING_INCLUDED - -#include -#include - -/* The support for explicit isn't that universal, and it isn't really - required - it is used to check that the TiXmlString class isn't incorrectly - used. Be nice to old compilers and macro it here: -*/ -#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - #define TIXML_EXPLICIT explicit -#elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - #define TIXML_EXPLICIT explicit -#else - #define TIXML_EXPLICIT -#endif - -namespace rospack_tinyxml { - -/* - TiXmlString is an emulation of a subset of the std::string template. - Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. - Only the member functions relevant to the TinyXML project have been implemented. - The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase - a string and there's no more room, we allocate a buffer twice as big as we need. -*/ -class TiXmlString -{ - public : - // The size type used - typedef size_t size_type; - - // Error value for find primitive - static const size_type npos; // = -1; - - - // TiXmlString empty constructor - TiXmlString () : rep_(&nullrep_) - { - } - - // TiXmlString copy constructor - TiXmlString ( const TiXmlString & copy) : rep_(0) - { - init(copy.length()); - memcpy(start(), copy.data(), length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) - { - init( static_cast( strlen(copy) )); - memcpy(start(), copy, length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) - { - init(len); - memcpy(start(), str, len); - } - - // TiXmlString destructor - ~TiXmlString () - { - quit(); - } - - // = operator - TiXmlString& operator = (const char * copy) - { - return assign( copy, (size_type)strlen(copy)); - } - - // = operator - TiXmlString& operator = (const TiXmlString & copy) - { - return assign(copy.start(), copy.length()); - } - - - // += operator. Maps to append - TiXmlString& operator += (const char * suffix) - { - return append(suffix, static_cast( strlen(suffix) )); - } - - // += operator. Maps to append - TiXmlString& operator += (char single) - { - return append(&single, 1); - } - - // += operator. Maps to append - TiXmlString& operator += (const TiXmlString & suffix) - { - return append(suffix.data(), suffix.length()); - } - - - // Convert a TiXmlString into a null-terminated char * - const char * c_str () const { return rep_->str; } - - // Convert a TiXmlString into a char * (need not be null terminated). - const char * data () const { return rep_->str; } - - // Return the length of a TiXmlString - size_type length () const { return rep_->size; } - - // Alias for length() - size_type size () const { return rep_->size; } - - // Checks if a TiXmlString is empty - bool empty () const { return rep_->size == 0; } - - // Return capacity of string - size_type capacity () const { return rep_->capacity; } - - - // single char extraction - const char& at (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // [] operator - char& operator [] (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // find a char in a string. Return TiXmlString::npos if not found - size_type find (char lookup) const - { - return find(lookup, 0); - } - - // find a char in a string from an offset. Return TiXmlString::npos if not found - size_type find (char tofind, size_type offset) const - { - if (offset >= length()) return npos; - - for (const char* p = c_str() + offset; *p != '\0'; ++p) - { - if (*p == tofind) return static_cast< size_type >( p - c_str() ); - } - return npos; - } - - void clear () - { - //Lee: - //The original was just too strange, though correct: - // TiXmlString().swap(*this); - //Instead use the quit & re-init: - quit(); - init(0,0); - } - - /* Function to reserve a big amount of data when we know we'll need it. Be aware that this - function DOES NOT clear the content of the TiXmlString if any exists. - */ - void reserve (size_type cap); - - TiXmlString& assign (const char* str, size_type len); - - TiXmlString& append (const char* str, size_type len); - - void swap (TiXmlString& other) - { - Rep* r = rep_; - rep_ = other.rep_; - other.rep_ = r; - } - - private: - - void init(size_type sz) { init(sz, sz); } - void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } - char* start() const { return rep_->str; } - char* finish() const { return rep_->str + rep_->size; } - - struct Rep - { - size_type size, capacity; - char str[1]; - }; - - void init(size_type sz, size_type cap) - { - if (cap) - { - // Lee: the original form: - // rep_ = static_cast(operator new(sizeof(Rep) + cap)); - // doesn't work in some cases of new being overloaded. Switching - // to the normal allocation, although use an 'int' for systems - // that are overly picky about structure alignment. - const size_type bytesNeeded = sizeof(Rep) + cap; - const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); - rep_ = reinterpret_cast( new int[ intsNeeded ] ); - - rep_->str[ rep_->size = sz ] = '\0'; - rep_->capacity = cap; - } - else - { - rep_ = &nullrep_; - } - } - - void quit() - { - if (rep_ != &nullrep_) - { - // The rep_ is really an array of ints. (see the allocator, above). - // Cast it back before delete, so the compiler won't incorrectly call destructors. - delete [] ( reinterpret_cast( rep_ ) ); - } - } - - Rep * rep_; - static Rep nullrep_; - -} ; - - -inline bool operator == (const TiXmlString & a, const TiXmlString & b) -{ - return ( a.length() == b.length() ) // optimization on some platforms - && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare -} -inline bool operator < (const TiXmlString & a, const TiXmlString & b) -{ - return strcmp(a.c_str(), b.c_str()) < 0; -} - -inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } -inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } -inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } -inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } - -inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } -inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } -inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } -inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); -TiXmlString operator + (const TiXmlString & a, const char* b); -TiXmlString operator + (const char* a, const TiXmlString & b); - - -/* - TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. - Only the operators that we need for TinyXML have been developped. -*/ -class TiXmlOutStream : public TiXmlString -{ -public : - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const TiXmlString & in) - { - *this += in; - return *this; - } - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const char * in) - { - *this += in; - return *this; - } - -} ; - -} - -#endif // TIXML_STRING_INCLUDED -#endif // TIXML_USE_STL diff --git a/tools/rospack/tinyxml-2.5.3/tinyxml.cpp b/tools/rospack/tinyxml-2.5.3/tinyxml.cpp deleted file mode 100644 index 0e0b6ba5..00000000 --- a/tools/rospack/tinyxml-2.5.3/tinyxml.cpp +++ /dev/null @@ -1,1891 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include - -#ifdef TIXML_USE_STL -#include -#include -#endif - -#include "tinyxml.h" - -namespace rospack_tinyxml { - -bool TiXmlBase::condenseWhiteSpace = true; - -// Microsoft compiler security -FILE* TiXmlFOpen( const char* filename, const char* mode ) -{ - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - FILE* fp = 0; - errno_t err = fopen_s( &fp, filename, mode ); - if ( !err && fp ) - return fp; - return 0; - #else - return fopen( filename, mode ); - #endif -} - -void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) -{ - int i=0; - - while( i<(int)str.length() ) - { - unsigned char c = (unsigned char) str[i]; - - if ( c == '&' - && i < ( (int)str.length() - 2 ) - && str[i+1] == '#' - && str[i+2] == 'x' ) - { - // Hexadecimal character reference. - // Pass through unchanged. - // © -- copyright symbol, for example. - // - // The -1 is a bug fix from Rob Laveaux. It keeps - // an overflow from happening if there is no ';'. - // There are actually 2 ways to exit this loop - - // while fails (error case) and break (semicolon found). - // However, there is no mechanism (currently) for - // this function to return an error. - while ( i<(int)str.length()-1 ) - { - outString->append( str.c_str() + i, 1 ); - ++i; - if ( str[i] == ';' ) - break; - } - } - else if ( c == '&' ) - { - outString->append( entity[0].str, entity[0].strLength ); - ++i; - } - else if ( c == '<' ) - { - outString->append( entity[1].str, entity[1].strLength ); - ++i; - } - else if ( c == '>' ) - { - outString->append( entity[2].str, entity[2].strLength ); - ++i; - } - else if ( c == '\"' ) - { - outString->append( entity[3].str, entity[3].strLength ); - ++i; - } - else if ( c == '\'' ) - { - outString->append( entity[4].str, entity[4].strLength ); - ++i; - } - else if ( c < 32 ) - { - // Easy pass at non-alpha/numeric/symbol - // Below 32 is symbolic. - char buf[ 32 ]; - - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); - #else - sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); - #endif - - //*ME: warning C4267: convert 'size_t' to 'int' - //*ME: Int-Cast to make compiler happy ... - outString->append( buf, (int)strlen( buf ) ); - ++i; - } - else - { - //char realc = (char) c; - //outString->append( &realc, 1 ); - *outString += (char) c; // somewhat more efficient function call. - ++i; - } - } -} - - -TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() -{ - parent = 0; - type = _type; - firstChild = 0; - lastChild = 0; - prev = 0; - next = 0; -} - - -TiXmlNode::~TiXmlNode() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } -} - - -void TiXmlNode::CopyTo( TiXmlNode* target ) const -{ - target->SetValue (value.c_str() ); - target->userData = userData; -} - - -void TiXmlNode::Clear() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } - - firstChild = 0; - lastChild = 0; -} - - -TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) -{ - assert( node->parent == 0 || node->parent == this ); - assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); - - if ( node->Type() == TiXmlNode::DOCUMENT ) - { - delete node; - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - node->parent = this; - - node->prev = lastChild; - node->next = 0; - - if ( lastChild ) - lastChild->next = node; - else - firstChild = node; // it was an empty list. - - lastChild = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) -{ - if ( addThis.Type() == TiXmlNode::DOCUMENT ) - { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - - return LinkEndChild( node ); -} - - -TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) -{ - if ( !beforeThis || beforeThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) - { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->next = beforeThis; - node->prev = beforeThis->prev; - if ( beforeThis->prev ) - { - beforeThis->prev->next = node; - } - else - { - assert( firstChild == beforeThis ); - firstChild = node; - } - beforeThis->prev = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) -{ - if ( !afterThis || afterThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) - { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->prev = afterThis; - node->next = afterThis->next; - if ( afterThis->next ) - { - afterThis->next->prev = node; - } - else - { - assert( lastChild == afterThis ); - lastChild = node; - } - afterThis->next = node; - return node; -} - - -TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) -{ - if ( replaceThis->parent != this ) - return 0; - - TiXmlNode* node = withThis.Clone(); - if ( !node ) - return 0; - - node->next = replaceThis->next; - node->prev = replaceThis->prev; - - if ( replaceThis->next ) - replaceThis->next->prev = node; - else - lastChild = node; - - if ( replaceThis->prev ) - replaceThis->prev->next = node; - else - firstChild = node; - - delete replaceThis; - node->parent = this; - return node; -} - - -bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) -{ - if ( removeThis->parent != this ) - { - assert( 0 ); - return false; - } - - if ( removeThis->next ) - removeThis->next->prev = removeThis->prev; - else - lastChild = removeThis->prev; - - if ( removeThis->prev ) - removeThis->prev->next = removeThis->next; - else - firstChild = removeThis->next; - - delete removeThis; - return true; -} - -const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = firstChild; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = lastChild; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild(); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling(); - } -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild( val ); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling( val ); - } -} - - -const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = next; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = prev; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -void TiXmlElement::RemoveAttribute( const char * name ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING str( name ); - TiXmlAttribute* node = attributeSet.Find( str ); - #else - TiXmlAttribute* node = attributeSet.Find( name ); - #endif - if ( node ) - { - attributeSet.Remove( node ); - delete node; - } -} - -const TiXmlElement* TiXmlNode::FirstChildElement() const -{ - const TiXmlNode* node; - - for ( node = FirstChild(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = FirstChild( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement() const -{ - const TiXmlNode* node; - - for ( node = NextSibling(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = NextSibling( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlDocument* TiXmlNode::GetDocument() const -{ - const TiXmlNode* node; - - for( node = this; node; node = node->parent ) - { - if ( node->ToDocument() ) - return node->ToDocument(); - } - return 0; -} - - -TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} - - -#ifdef TIXML_USE_STL -TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} -#endif - - -TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::ELEMENT ) -{ - firstChild = lastChild = 0; - copy.CopyTo( this ); -} - - -void TiXmlElement::operator=( const TiXmlElement& base ) -{ - ClearThis(); - base.CopyTo( this ); -} - - -TiXmlElement::~TiXmlElement() -{ - ClearThis(); -} - - -void TiXmlElement::ClearThis() -{ - Clear(); - while( attributeSet.First() ) - { - TiXmlAttribute* node = attributeSet.First(); - attributeSet.Remove( node ); - delete node; - } -} - - -const char* TiXmlElement::Attribute( const char* name ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return node->Value(); - return 0; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return &node->ValueStr(); - return 0; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, int* i ) const -{ - const char* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s ); - } - else { - *i = 0; - } - } - return s; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const -{ - const std::string* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s->c_str() ); - } - else { - *i = 0; - } - } - return s; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, double* d ) const -{ - const char* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s ); - } - else { - *d = 0; - } - } - return s; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const -{ - const std::string* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s->c_str() ); - } - else { - *d = 0; - } - } - return s; -} -#endif - - -int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); -} - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); -} -#endif - - -int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); -} - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); -} -#endif - - -void TiXmlElement::SetAttribute( const char * name, int val ) -{ - char buf[64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); - #else - sprintf( buf, "%d", val ); - #endif - SetAttribute( name, buf ); -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, int val ) -{ - std::ostringstream oss; - oss << val; - SetAttribute( name, oss.str() ); -} -#endif - - -void TiXmlElement::SetDoubleAttribute( const char * name, double val ) -{ - char buf[256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); - #else - sprintf( buf, "%f", val ); - #endif - SetAttribute( name, buf ); -} - - -void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING _name( cname ); - TIXML_STRING _value( cvalue ); - #else - const char* _name = cname; - const char* _value = cvalue; - #endif - - TiXmlAttribute* node = attributeSet.Find( _name ); - if ( node ) - { - node->SetValue( _value ); - return; - } - - TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) -{ - TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - { - node->SetValue( _value ); - return; - } - - TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); - } -} -#endif - - -void TiXmlElement::Print( FILE* cfile, int depth ) const -{ - int i; - assert( cfile ); - for ( i=0; iNext() ) - { - fprintf( cfile, " " ); - attrib->Print( cfile, depth ); - } - - // There are 3 different formatting approaches: - // 1) An element without children is printed as a node - // 2) An element with only a text child is printed as text - // 3) An element with children is printed on multiple lines. - TiXmlNode* node; - if ( !firstChild ) - { - fprintf( cfile, " />" ); - } - else if ( firstChild == lastChild && firstChild->ToText() ) - { - fprintf( cfile, ">" ); - firstChild->Print( cfile, depth + 1 ); - fprintf( cfile, "", value.c_str() ); - } - else - { - fprintf( cfile, ">" ); - - for ( node = firstChild; node; node=node->NextSibling() ) - { - if ( !node->ToText() ) - { - fprintf( cfile, "\n" ); - } - node->Print( cfile, depth+1 ); - } - fprintf( cfile, "\n" ); - for( i=0; i", value.c_str() ); - } -} - - -void TiXmlElement::CopyTo( TiXmlElement* target ) const -{ - // superclass: - TiXmlNode::CopyTo( target ); - - // Element class: - // Clone the attributes, then clone the children. - const TiXmlAttribute* attribute = 0; - for( attribute = attributeSet.First(); - attribute; - attribute = attribute->Next() ) - { - target->SetAttribute( attribute->Name(), attribute->Value() ); - } - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - -bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this, attributeSet.First() ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -TiXmlNode* TiXmlElement::Clone() const -{ - TiXmlElement* clone = new TiXmlElement( Value() ); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -const char* TiXmlElement::GetText() const -{ - const TiXmlNode* child = this->FirstChild(); - if ( child ) { - const TiXmlText* childText = child->ToText(); - if ( childText ) { - return childText->Value(); - } - } - return 0; -} - - -TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - ClearError(); -} - -TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} - - -#ifdef TIXML_USE_STL -TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} -#endif - - -TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) -{ - copy.CopyTo( this ); -} - - -void TiXmlDocument::operator=( const TiXmlDocument& copy ) -{ - Clear(); - copy.CopyTo( this ); -} - - -bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) -{ - // See STL_STRING_BUG below. - //StringToBuffer buf( value ); - - return LoadFile( Value(), encoding ); -} - - -bool TiXmlDocument::SaveFile() const -{ - // See STL_STRING_BUG below. -// StringToBuffer buf( value ); -// -// if ( buf.buffer && SaveFile( buf.buffer ) ) -// return true; -// -// return false; - return SaveFile( Value() ); -} - -bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) -{ - // There was a really terrifying little bug here. The code: - // value = filename - // in the STL case, cause the assignment method of the std::string to - // be called. What is strange, is that the std::string had the same - // address as it's c_str() method, and so bad things happen. Looks - // like a bug in the Microsoft STL implementation. - // Add an extra string to avoid the crash. - TIXML_STRING filename( _filename ); - value = filename; - - // reading in binary mode so that tinyxml can normalize the EOL - FILE* file = TiXmlFOpen( value.c_str (), "rb" ); - - if ( file ) - { - bool result = LoadFile( file, encoding ); - fclose( file ); - return result; - } - else - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } -} - -bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) -{ - if ( !file ) - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Delete the existing data: - Clear(); - location.Clear(); - - // Get the file size, so we can pre-allocate the string. HUGE speed impact. - long length = 0; - fseek( file, 0, SEEK_END ); - length = ftell( file ); - fseek( file, 0, SEEK_SET ); - - // Strange case, but good to handle up front. - if ( length <= 0 ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // If we have a file, assume it is all one big XML file, and read it in. - // The document parser may decide the document ends sooner than the entire file, however. - TIXML_STRING data; - data.reserve( length ); - - // Subtle bug here. TinyXml did use fgets. But from the XML spec: - // 2.11 End-of-Line Handling - // - // - // ...the XML processor MUST behave as if it normalized all line breaks in external - // parsed entities (including the document entity) on input, before parsing, by translating - // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to - // a single #xA character. - // - // - // It is not clear fgets does that, and certainly isn't clear it works cross platform. - // Generally, you expect fgets to translate from the convention of the OS to the c/unix - // convention, and not work generally. - - /* - while( fgets( buf, sizeof(buf), file ) ) - { - data += buf; - } - */ - - char* buf = new char[ length+1 ]; - buf[0] = 0; - - if ( fread( buf, length, 1, file ) != 1 ) { - delete [] buf; - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - const char* lastPos = buf; - const char* p = buf; - - buf[length] = 0; - while( *p ) { - assert( p < (buf+length) ); - if ( *p == 0xa ) { - // Newline character. No special rules for this. Append all the characters - // since the last string, and include the newline. - data.append( lastPos, (p-lastPos+1) ); // append, include the newline - ++p; // move past the newline - lastPos = p; // and point to the new buffer (may be 0) - assert( p <= (buf+length) ); - } - else if ( *p == 0xd ) { - // Carriage return. Append what we have so far, then - // handle moving forward in the buffer. - if ( (p-lastPos) > 0 ) { - data.append( lastPos, p-lastPos ); // do not add the CR - } - data += (char)0xa; // a proper newline - - if ( *(p+1) == 0xa ) { - // Carriage return - new line sequence - p += 2; - lastPos = p; - assert( p <= (buf+length) ); - } - else { - // it was followed by something else...that is presumably characters again. - ++p; - lastPos = p; - assert( p <= (buf+length) ); - } - } - else { - ++p; - } - } - // Handle any left over characters. - if ( p-lastPos ) { - data.append( lastPos, p-lastPos ); - } - delete [] buf; - buf = 0; - - Parse( data.c_str(), 0, encoding ); - - if ( Error() ) - return false; - else - return true; -} - - -bool TiXmlDocument::SaveFile( const char * filename ) const -{ - // The old c stuff lives on... - FILE* fp = TiXmlFOpen( filename, "w" ); - if ( fp ) - { - bool result = SaveFile( fp ); - fclose( fp ); - return result; - } - return false; -} - - -bool TiXmlDocument::SaveFile( FILE* fp ) const -{ - if ( useMicrosoftBOM ) - { - const unsigned char TIXML_UTF_LEAD_0 = 0xefU; - const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; - const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - - fputc( TIXML_UTF_LEAD_0, fp ); - fputc( TIXML_UTF_LEAD_1, fp ); - fputc( TIXML_UTF_LEAD_2, fp ); - } - Print( fp, 0 ); - return (ferror(fp) == 0); -} - - -void TiXmlDocument::CopyTo( TiXmlDocument* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->error = error; - target->errorId = errorId; - target->errorDesc = errorDesc; - target->tabsize = tabsize; - target->errorLocation = errorLocation; - target->useMicrosoftBOM = useMicrosoftBOM; - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - - -TiXmlNode* TiXmlDocument::Clone() const -{ - TiXmlDocument* clone = new TiXmlDocument(); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlDocument::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - node->Print( cfile, depth ); - fprintf( cfile, "\n" ); - } -} - - -bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -const TiXmlAttribute* TiXmlAttribute::Next() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} - -/* -TiXmlAttribute* TiXmlAttribute::Next() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} -*/ - -const TiXmlAttribute* TiXmlAttribute::Previous() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} - -/* -TiXmlAttribute* TiXmlAttribute::Previous() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} -*/ - -void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - TIXML_STRING n, v; - - EncodeString( name, &n ); - EncodeString( value, &v ); - - if (value.find ('\"') == TIXML_STRING::npos) { - if ( cfile ) { - fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; - } - } - else { - if ( cfile ) { - fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; - } - } -} - - -int TiXmlAttribute::QueryIntValue( int* ival ) const -{ - if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -int TiXmlAttribute::QueryDoubleValue( double* dval ) const -{ - if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -void TiXmlAttribute::SetIntValue( int _value ) -{ - char buf [64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); - #else - sprintf (buf, "%d", _value); - #endif - SetValue (buf); -} - -void TiXmlAttribute::SetDoubleValue( double _value ) -{ - char buf [256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); - #else - sprintf (buf, "%lf", _value); - #endif - SetValue (buf); -} - -int TiXmlAttribute::IntValue() const -{ - return atoi (value.c_str ()); -} - -double TiXmlAttribute::DoubleValue() const -{ - return atof (value.c_str ()); -} - - -TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) -{ - copy.CopyTo( this ); -} - - -void TiXmlComment::operator=( const TiXmlComment& base ) -{ - Clear(); - base.CopyTo( this ); -} - - -void TiXmlComment::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlComment::CopyTo( TiXmlComment* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlComment::Clone() const -{ - TiXmlComment* clone = new TiXmlComment(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlText::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - if ( cdata ) - { - int i; - fprintf( cfile, "\n" ); - for ( i=0; i\n", value.c_str() ); // unformatted output - } - else - { - TIXML_STRING buffer; - EncodeString( value, &buffer ); - fprintf( cfile, "%s", buffer.c_str() ); - } -} - - -void TiXmlText::CopyTo( TiXmlText* target ) const -{ - TiXmlNode::CopyTo( target ); - target->cdata = cdata; -} - - -bool TiXmlText::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlText::Clone() const -{ - TiXmlText* clone = 0; - clone = new TiXmlText( "" ); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlDeclaration::TiXmlDeclaration( const char * _version, - const char * _encoding, - const char * _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} - - -#ifdef TIXML_USE_STL -TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} -#endif - - -TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::DECLARATION ) -{ - copy.CopyTo( this ); -} - - -void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) -{ - Clear(); - copy.CopyTo( this ); -} - - -void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - if ( cfile ) fprintf( cfile, "" ); - if ( str ) (*str) += "?>"; -} - - -void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->version = version; - target->encoding = encoding; - target->standalone = standalone; -} - - -bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlDeclaration::Clone() const -{ - TiXmlDeclaration* clone = new TiXmlDeclaration(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlUnknown::Print( FILE* cfile, int depth ) const -{ - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlUnknown::Clone() const -{ - TiXmlUnknown* clone = new TiXmlUnknown(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlAttributeSet::TiXmlAttributeSet() -{ - sentinel.next = &sentinel; - sentinel.prev = &sentinel; -} - - -TiXmlAttributeSet::~TiXmlAttributeSet() -{ - assert( sentinel.next == &sentinel ); - assert( sentinel.prev == &sentinel ); -} - - -void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) -{ - #ifdef TIXML_USE_STL - assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. - #else - assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. - #endif - - addMe->next = &sentinel; - addMe->prev = sentinel.prev; - - sentinel.prev->next = addMe; - sentinel.prev = addMe; -} - -void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) -{ - TiXmlAttribute* node; - - for( node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node == removeMe ) - { - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; - return; - } - } - assert( 0 ); // we tried to remove a non-linked attribute. -} - - -#ifdef TIXML_USE_STL -const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const -{ - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; - } - return 0; -} - -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; - } - return 0; -} -*/ -#endif - - -const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const -{ - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; - } - return 0; -} - -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; - } - return 0; -} -*/ - -#ifdef TIXML_USE_STL -std::istream& operator>> (std::istream & in, TiXmlNode & base) -{ - TIXML_STRING tag; - tag.reserve( 8 * 1000 ); - base.StreamIn( &in, &tag ); - - base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); - return in; -} -#endif - - -#ifdef TIXML_USE_STL -std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out << printer.Str(); - - return out; -} - - -std::string& operator<< (std::string& out, const TiXmlNode& base ) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out.append( printer.Str() ); - - return out; -} -#endif - - -TiXmlHandle TiXmlHandle::FirstChild() const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement() const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild(); - for ( i=0; - child && iNextSibling(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild( value ); - for ( i=0; - child && iNextSibling( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement(); - for ( i=0; - child && iNextSiblingElement(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement( value ); - for ( i=0; - child && iNextSiblingElement( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) -{ - DoIndent(); - buffer += "<"; - buffer += element.Value(); - - for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) - { - buffer += " "; - attrib->Print( 0, 0, &buffer ); - } - - if ( !element.FirstChild() ) - { - buffer += " />"; - DoLineBreak(); - } - else - { - buffer += ">"; - if ( element.FirstChild()->ToText() - && element.LastChild() == element.FirstChild() - && element.FirstChild()->ToText()->CDATA() == false ) - { - simpleTextPrint = true; - // no DoLineBreak()! - } - else - { - DoLineBreak(); - } - } - ++depth; - return true; -} - - -bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) -{ - --depth; - if ( !element.FirstChild() ) - { - // nothing. - } - else - { - if ( simpleTextPrint ) - { - simpleTextPrint = false; - } - else - { - DoIndent(); - } - buffer += ""; - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlText& text ) -{ - if ( text.CDATA() ) - { - DoIndent(); - buffer += ""; - DoLineBreak(); - } - else if ( simpleTextPrint ) - { - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - } - else - { - DoIndent(); - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) -{ - DoIndent(); - declaration.Print( 0, 0, &buffer ); - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlComment& comment ) -{ - DoIndent(); - buffer += ""; - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) -{ - DoIndent(); - buffer += "<"; - buffer += unknown.Value(); - buffer += ">"; - DoLineBreak(); - return true; -} - -} - diff --git a/tools/rospack/tinyxml-2.5.3/tinyxml.h b/tools/rospack/tinyxml-2.5.3/tinyxml.h deleted file mode 100644 index dae416c5..00000000 --- a/tools/rospack/tinyxml-2.5.3/tinyxml.h +++ /dev/null @@ -1,1818 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef ROSPACK_TINYXML_INCLUDED -#define ROSPACK_TINYXML_INCLUDED - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4530 ) -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include - -// Help out windows: -#if defined( _DEBUG ) && !defined( DEBUG ) -#define DEBUG -#endif - -#ifdef TIXML_USE_STL - #include - #include - #include - #define TIXML_STRING std::string -#else - #include "tinystr.h" - #define TIXML_STRING TiXmlString -#endif - -// Deprecated library function hell. Compilers want to use the -// new safe versions. This probably doesn't fully address the problem, -// but it gets closer. There are too many compilers for me to fully -// test. If you get compilation troubles, undefine TIXML_SAFE -#define TIXML_SAFE - -#ifdef TIXML_SAFE - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - // Microsoft visual studio, version 2005 and higher. - #define TIXML_SNPRINTF _snprintf_s - #define TIXML_SNSCANF _snscanf_s - #define TIXML_SSCANF sscanf_s - #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - //#pragma message( "Using _sn* functions." ) - #define TIXML_SNPRINTF _snprintf - #define TIXML_SNSCANF _snscanf - #define TIXML_SSCANF sscanf - #elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - //#warning( "Using sn* functions." ) - #define TIXML_SNPRINTF snprintf - #define TIXML_SNSCANF snscanf - #define TIXML_SSCANF sscanf - #else - #define TIXML_SSCANF sscanf - #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 - - -namespace rospack_tinyxml { - -class TiXmlDocument; -class TiXmlElement; -class TiXmlComment; -class TiXmlUnknown; -class TiXmlAttribute; -class TiXmlText; -class TiXmlDeclaration; -class TiXmlParsingData; - -const int TIXML_MAJOR_VERSION = 2; -const int TIXML_MINOR_VERSION = 5; -const int TIXML_PATCH_VERSION = 3; - -/* Internal structure for tracking location of items - in the XML file. -*/ -struct TiXmlCursor -{ - TiXmlCursor() { Clear(); } - void Clear() { row = col = -1; } - - int row; // 0 based. - int col; // 0 based. -}; - - -/** - If you call the Accept() method, it requires being passed a TiXmlVisitor - class to handle callbacks. For nodes that contain other nodes (Document, Element) - you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves - are simple called with Visit(). - - If you return 'true' from a Visit method, recursive parsing will continue. If you return - false, no children of this node or its sibilings will be Visited. - - All flavors of Visit methods have a default implementation that returns 'true' (continue - visiting). You need to only override methods that are interesting to you. - - Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. - - You should never change the document from a callback. - - @sa TiXmlNode::Accept() -*/ -class TINYXML_EXPORT TiXmlVisitor -{ -public: - virtual ~TiXmlVisitor() {} - - /// Visit a document. - virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } - /// Visit a document. - virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } - - /// Visit an element. - virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } - /// Visit an element. - virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } - - /// Visit a declaration - virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } - /// Visit a text node - virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } - /// Visit a comment node - virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } - /// Visit an unknow node - virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } -}; - -// Only used by Attribute::Query functions -enum -{ - TIXML_SUCCESS, - TIXML_NO_ATTRIBUTE, - TIXML_WRONG_TYPE -}; - - -// Used by the parsing routines. -enum TiXmlEncoding -{ - TIXML_ENCODING_UNKNOWN, - TIXML_ENCODING_UTF8, - TIXML_ENCODING_LEGACY -}; - -const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; - -/** TiXmlBase is a base class for every class in TinyXml. - It does little except to establish that TinyXml classes - can be printed and provide some utility functions. - - In XML, the document and elements can contain - other elements and other types of nodes. - - @verbatim - A Document can contain: Element (container or leaf) - Comment (leaf) - Unknown (leaf) - Declaration( leaf ) - - An Element can contain: Element (container or leaf) - Text (leaf) - Attributes (not on tree) - Comment (leaf) - Unknown (leaf) - - A Decleration contains: Attributes (not on tree) - @endverbatim -*/ -class TINYXML_EXPORT TiXmlBase -{ - friend class TiXmlNode; - friend class TiXmlElement; - friend class TiXmlDocument; - -public: - TiXmlBase() : userData(0) {} - virtual ~TiXmlBase() {} - - /** All TinyXml classes can print themselves to a filestream - or the string class (TiXmlString in non-STL mode, std::string - in STL mode.) Either or both cfile and str can be null. - - This is a formatted print, and will insert - tabs and newlines. - - (For an unformatted stream, use the << operator.) - */ - virtual void Print( FILE* cfile, int depth ) const = 0; - - /** The world does not agree on whether white space should be kept or - not. In order to make everyone happy, these global, static functions - are provided to set whether or not TinyXml will condense all white space - into a single space or not. The default is to condense. Note changing this - value is not thread safe. - */ - static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } - - /// Return the current white space setting. - static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } - - /** Return the position, in the original source file, of this node or attribute. - The row and column are 1-based. (That is the first row and first column is - 1,1). If the returns values are 0 or less, then the parser does not have - a row and column value. - - Generally, the row and column value will be set when the TiXmlDocument::Load(), - TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set - when the DOM was created from operator>>. - - The values reflect the initial load. Once the DOM is modified programmatically - (by adding or changing nodes and attributes) the new values will NOT update to - reflect changes in the document. - - There is a minor performance cost to computing the row and column. Computation - can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. - - @sa TiXmlDocument::SetTabSize() - */ - int Row() const { return location.row + 1; } - int Column() const { return location.col + 1; } ///< See Row() - - void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. - 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 returns, for a given lead byte, the total number of bytes - // in the UTF-8 sequence. - static const int utf8ByteTable[256]; - - virtual const char* Parse( const char* p, - TiXmlParsingData* data, - TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; - - /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, - or they will be transformed into entities! - */ - static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); - - enum - { - TIXML_NO_ERROR = 0, - TIXML_ERROR, - TIXML_ERROR_OPENING_FILE, - TIXML_ERROR_OUT_OF_MEMORY, - TIXML_ERROR_PARSING_ELEMENT, - TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, - TIXML_ERROR_READING_ELEMENT_VALUE, - TIXML_ERROR_READING_ATTRIBUTES, - TIXML_ERROR_PARSING_EMPTY, - TIXML_ERROR_READING_END_TAG, - TIXML_ERROR_PARSING_UNKNOWN, - TIXML_ERROR_PARSING_COMMENT, - TIXML_ERROR_PARSING_DECLARATION, - TIXML_ERROR_DOCUMENT_EMPTY, - TIXML_ERROR_EMBEDDED_NULL, - TIXML_ERROR_PARSING_CDATA, - TIXML_ERROR_DOCUMENT_TOP_ONLY, - - TIXML_ERROR_STRING_COUNT - }; - -protected: - - static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); - inline static bool IsWhiteSpace( char c ) - { - return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); - } - inline static bool IsWhiteSpace( int c ) - { - if ( c < 256 ) - return IsWhiteSpace( (char) c ); - return false; // Again, only truly correct for English/Latin...but usually works. - } - - #ifdef TIXML_USE_STL - static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); - static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); - #endif - - /* Reads an XML name into the string provided. Returns - a pointer just past the last character of the name, - or 0 if the function has an error. - */ - static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); - - /* Reads text. Returns a pointer past the given end tag. - Wickedly complex options, but it keeps the (sensitive) code in one place. - */ - static const char* ReadText( const char* in, // where to start - TIXML_STRING* text, // the string read - bool ignoreWhiteSpace, // whether to keep the white space - const char* endTag, // what ends this text - bool ignoreCase, // whether to ignore case in the end tag - TiXmlEncoding encoding ); // the current encoding - - // If an entity has been found, transform it into a character. - static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); - - // Get a character, while interpreting entities. - // The length can be from 0 to 4 bytes. - inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) - { - assert( p ); - if ( encoding == TIXML_ENCODING_UTF8 ) - { - *length = utf8ByteTable[ *((const unsigned char*)p) ]; - assert( *length >= 0 && *length < 5 ); - } - else - { - *length = 1; - } - - if ( *length == 1 ) - { - if ( *p == '&' ) - return GetEntity( p, _value, length, encoding ); - *_value = *p; - return p+1; - } - else if ( *length ) - { - //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), - // and the null terminator isn't needed - for( int i=0; p[i] && i<*length; ++i ) { - _value[i] = p[i]; - } - return p + (*length); - } - else - { - // Not valid text. - return 0; - } - } - - // Return true if the next characters in the stream are any of the endTag sequences. - // Ignore case only works for english, and should only be relied on when comparing - // to English words: StringEqual( p, "version", true ) is fine. - static bool StringEqual( const char* p, - const char* endTag, - bool ignoreCase, - TiXmlEncoding encoding ); - - static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; - - TiXmlCursor location; - - /// Field containing a generic user pointer - void* userData; - - // None of these methods are reliable for any language except English. - // Good for approximation, not great for accuracy. - static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); - static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); - inline static int ToLower( int v, TiXmlEncoding encoding ) - { - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( v < 128 ) return tolower( v ); - return v; - } - else - { - return tolower( v ); - } - } - static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); - -private: - TiXmlBase( const TiXmlBase& ); // not implemented. - void operator=( const TiXmlBase& base ); // not allowed. - - struct Entity - { - const char* str; - unsigned int strLength; - char chr; - }; - enum - { - NUM_ENTITY = 5, - MAX_ENTITY_LENGTH = 6 - - }; - static Entity entity[ NUM_ENTITY ]; - static bool condenseWhiteSpace; -}; - - -/** The parent class for everything in the Document Object Model. - (Except for attributes). - Nodes have siblings, a parent, and children. A node can be - 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 TINYXML_EXPORT TiXmlNode : public TiXmlBase -{ - friend class TiXmlDocument; - friend class TiXmlElement; - -public: - #ifdef TIXML_USE_STL - - /** An input stream operator, for every class. Tolerant of newlines and - formatting, but doesn't expect them. - */ - friend std::istream& operator >> (std::istream& in, TiXmlNode& base); - - /** An output stream operator, for every class. Note that this outputs - without any newlines or formatting, as opposed to Print(), which - includes tabs and new lines. - - The operator<< and operator>> are not completely symmetric. Writing - a node to a stream is very well defined. You'll get a nice stream - of output, without any extra whitespace or newlines. - - But reading is not as well defined. (As it always is.) If you create - a TiXmlElement (for example) and read that from an input stream, - the text needs to define an element or junk will result. This is - true of all input streams, but it's worth keeping in mind. - - A TiXmlDocument will read nodes until it reads a root element, and - all the children of that root element. - */ - friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); - - /// Appends the XML node or attribute to a std::string. - friend std::string& operator<< (std::string& out, const TiXmlNode& base ); - - #endif - - /** The types of XML nodes supported by TinyXml. (All the - unsupported types are picked up by UNKNOWN.) - */ - enum NodeType - { - DOCUMENT, - ELEMENT, - COMMENT, - UNKNOWN, - TEXT, - DECLARATION, - TYPECOUNT - }; - - virtual ~TiXmlNode(); - - /** The meaning of 'value' changes for the specific type of - TiXmlNode. - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - - The subclasses will wrap this function. - */ - const char *Value() const { return value.c_str (); } - - #ifdef TIXML_USE_STL - /** Return Value() as a std::string. If you only use STL, - this is more efficient than calling Value(). - Only available in STL mode. - */ - const std::string& ValueStr() const { return value; } - #endif - - const TIXML_STRING& ValueTStr() const { return value; } - - /** Changes the value of the node. Defined as: - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - */ - void SetValue(const char * _value) { value = _value;} - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Delete all the children of this node. Does not affect 'this'. - void Clear(); - - /// One step up the DOM. - TiXmlNode* Parent() { return parent; } - const TiXmlNode* Parent() const { return parent; } - - const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. - TiXmlNode* FirstChild() { return firstChild; } - const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. - /// The first child of this node with the matching 'value'. Will be null if none found. - TiXmlNode* FirstChild( const char * _value ) { - // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) - // call the method, cast the return back to non-const. - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); - } - const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. - TiXmlNode* LastChild() { return lastChild; } - - const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. - TiXmlNode* LastChild( const char * _value ) { - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. - #endif - - /** An alternate way to walk the children of a node. - One way to iterate over nodes is: - @verbatim - for( child = parent->FirstChild(); child; child = child->NextSibling() ) - @endverbatim - - IterateChildren does the same thing with the syntax: - @verbatim - child = 0; - while( child = parent->IterateChildren( child ) ) - @endverbatim - - IterateChildren takes the previous child as input and finds - the next one. If the previous child is null, it returns the - first. IterateChildren will return null when done. - */ - const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); - } - - /// This flavor of IterateChildren searches for children with a particular 'value' - const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - #endif - - /** Add a new node related to this. Adds a child past the LastChild. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); - - - /** Add a new node related to this. Adds a child past the LastChild. - - NOTE: the node to be added is passed by pointer, and will be - henceforth owned (and deleted) by tinyXml. This method is efficient - and avoids an extra copy, but should be used with care as it - uses a different memory model than the other insert functions. - - @sa InsertEndChild - */ - TiXmlNode* LinkEndChild( TiXmlNode* addThis ); - - /** Add a new node related to this. Adds a child before the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); - - /** Add a new node related to this. Adds a child after the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); - - /** Replace a child of this node. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); - - /// Delete a child of this node. - bool RemoveChild( TiXmlNode* removeThis ); - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling() const { return prev; } - TiXmlNode* PreviousSibling() { return prev; } - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling( const char * ) const; - TiXmlNode* PreviousSibling( const char *_prev ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Navigate to a sibling node. - const TiXmlNode* NextSibling() const { return next; } - TiXmlNode* NextSibling() { return next; } - - /// Navigate to a sibling node with the given 'value'. - const TiXmlNode* NextSibling( const char * ) const; - TiXmlNode* NextSibling( const char* _next ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement() const; - TiXmlElement* NextSiblingElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement( const char * ) const; - TiXmlElement* NextSiblingElement( const char *_next ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement() const; - TiXmlElement* FirstChildElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); - } - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement( const char * _value ) const; - TiXmlElement* FirstChildElement( const char * _value ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /** Query the type (as an enumerated value, above) of this node. - The possible types are: DOCUMENT, ELEMENT, COMMENT, - UNKNOWN, TEXT, and DECLARATION. - */ - int Type() const { return type; } - - /** Return a pointer to the Document this node lives in. - Returns null if not in a document. - */ - const TiXmlDocument* GetDocument() const; - TiXmlDocument* GetDocument() { - return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); - } - - /// Returns true if this node has no children. - bool NoChildren() const { return !firstChild; } - - virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - /** Create an exact duplicate of this node and return it. The memory must be deleted - by the caller. - */ - virtual TiXmlNode* Clone() const = 0; - - /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the - XML tree will be conditionally visited and the host will be called back - via the TiXmlVisitor interface. - - This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse - the XML for the callbacks, so the performance of TinyXML is unchanged by using this - interface versus any other.) - - The interface has been based on ideas from: - - - http://www.saxproject.org/ - - http://c2.com/cgi/wiki?HierarchicalVisitorPattern - - Which are both good references for "visiting". - - An example of using Accept(): - @verbatim - TiXmlPrinter printer; - tinyxmlDoc.Accept( &printer ); - const char* xmlcstr = printer.CStr(); - @endverbatim - */ - virtual bool Accept( TiXmlVisitor* visitor ) const = 0; - -protected: - TiXmlNode( NodeType _type ); - - // Copy to the allocated object. Shared functionality between Clone, Copy constructor, - // and the assignment operator. - void CopyTo( TiXmlNode* target ) const; - - #ifdef TIXML_USE_STL - // The real work of the input operator. - virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; - #endif - - // Figure out what is at *p, and parse it. Returns null if it is not an xml node. - TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); - - TiXmlNode* parent; - NodeType type; - - TiXmlNode* firstChild; - TiXmlNode* lastChild; - - TIXML_STRING value; - - TiXmlNode* prev; - TiXmlNode* next; - -private: - TiXmlNode( const TiXmlNode& ); // not implemented. - void operator=( const TiXmlNode& base ); // not allowed. -}; - - -/** An attribute is a name-value pair. Elements have an arbitrary - number of attributes, each with a unique name. - - @note The attributes are not TiXmlNodes, since they are not - part of the tinyXML document object model. There are other - suggested ways to look at this problem. -*/ -class TINYXML_EXPORT TiXmlAttribute : public TiXmlBase -{ - friend class TiXmlAttributeSet; - -public: - /// Construct an empty attribute. - TiXmlAttribute() : TiXmlBase() - { - document = 0; - prev = next = 0; - } - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlAttribute( const std::string& _name, const std::string& _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - #endif - - /// Construct an attribute with a name and value. - TiXmlAttribute( const char * _name, const char * _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - - const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. - const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. - #ifdef TIXML_USE_STL - const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. - #endif - int IntValue() const; ///< Return the value of this attribute, converted to an integer. - double DoubleValue() const; ///< Return the value of this attribute, converted to a double. - - // Get the tinyxml string representation - const TIXML_STRING& NameTStr() const { return name; } - - /** QueryIntValue examines the value string. It is an alternative to the - IntValue() method with richer error checking. - If the value is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. - - A specialized but useful call. Note that for success it returns 0, - which is the opposite of almost all other TinyXml calls. - */ - int QueryIntValue( int* _value ) const; - /// QueryDoubleValue examines the value string. See QueryIntValue(). - int QueryDoubleValue( double* _value ) const; - - void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. - void SetValue( const char* _value ) { value = _value; } ///< Set the value. - - void SetIntValue( int _value ); ///< Set the value from an integer. - void SetDoubleValue( double _value ); ///< Set the value from a double. - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetName( const std::string& _name ) { name = _name; } - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Get the next sibling attribute in the DOM. Returns null at end. - const TiXmlAttribute* Next() const; - TiXmlAttribute* Next() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); - } - - /// Get the previous sibling attribute in the DOM. Returns null at beginning. - const TiXmlAttribute* Previous() const; - TiXmlAttribute* Previous() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); - } - - bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } - bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } - bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } - - /* Attribute parsing starts: first letter of the name - returns: the next char after the value end quote - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - // Prints this Attribute to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - - // [internal use] - // Set the document pointer so the attribute can report errors. - void SetDocument( TiXmlDocument* doc ) { document = doc; } - -private: - TiXmlAttribute( const TiXmlAttribute& ); // not implemented. - void operator=( const TiXmlAttribute& base ); // not allowed. - - TiXmlDocument* document; // A pointer back to a document, for error reporting. - TIXML_STRING name; - TIXML_STRING value; - TiXmlAttribute* prev; - TiXmlAttribute* next; -}; - - -/* A class used to manage a group of attributes. - It is only used internally, both by the ELEMENT and the DECLARATION. - - The set can be changed transparent to the Element and Declaration - classes that use it, but NOT transparent to the Attribute - which has to implement a next() and previous() method. Which makes - it a bit problematic and prevents the use of STL. - - This version is implemented with circular lists because: - - I like circular lists - - it demonstrates some independence from the (typical) doubly linked list. -*/ -class TINYXML_EXPORT TiXmlAttributeSet -{ -public: - TiXmlAttributeSet(); - ~TiXmlAttributeSet(); - - void Add( TiXmlAttribute* attribute ); - void Remove( TiXmlAttribute* attribute ); - - const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - - const TiXmlAttribute* Find( const char* _name ) const; - TiXmlAttribute* Find( const char* _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } - #ifdef TIXML_USE_STL - const TiXmlAttribute* Find( const std::string& _name ) const; - TiXmlAttribute* Find( const std::string& _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } - - #endif - -private: - //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), - //*ME: this class must be also use a hidden/disabled copy-constructor !!! - TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed - void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) - - TiXmlAttribute sentinel; -}; - - -/** The element is a container class. It has a value, the element name, - and can contain other elements, text, comments, and unknowns. - Elements also contain an arbitrary number of attributes. -*/ -class TINYXML_EXPORT TiXmlElement : public TiXmlNode -{ -public: - /// Construct an element. - TiXmlElement (const char * in_value); - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlElement( const std::string& _value ); - #endif - - TiXmlElement( const TiXmlElement& ); - - void operator=( const TiXmlElement& base ); - - virtual ~TiXmlElement(); - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - */ - const char* Attribute( const char* name ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an integer, - the integer value will be put in the return 'i', if 'i' - is non-null. - */ - const char* Attribute( const char* name, int* i ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an double, - the double value will be put in the return 'd', if 'd' - is non-null. - */ - const char* Attribute( const char* name, double* d ) const; - - /** QueryIntAttribute examines the attribute - it is an alternative to the - Attribute() method with richer error checking. - If the attribute is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. If the attribute - does not exist, then TIXML_NO_ATTRIBUTE is returned. - */ - int QueryIntAttribute( const char* name, int* _value ) const; - /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). - int QueryDoubleAttribute( const char* name, double* _value ) const; - /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). - int QueryFloatAttribute( const char* name, float* _value ) const { - double d; - int result = QueryDoubleAttribute( name, &d ); - if ( result == TIXML_SUCCESS ) { - *_value = (float)d; - } - return result; - } - - #ifdef TIXML_USE_STL - /** Template form of the attribute query which will try to read the - attribute into the specified type. Very easy, very powerful, but - be careful to make sure to call this with the correct type. - - NOTE: This method doesn't work correctly for 'string' types. - - @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE - */ - template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const - { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - std::stringstream sstream( node->ValueStr() ); - sstream >> *outValue; - if ( !sstream.fail() ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; - } - /* - This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string" - but template specialization is hard to get working cross-compiler. Leaving the bug for now. - - // The above will fail for std::string because the space character is used as a seperator. - // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string - template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const - { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - *outValue = node->ValueStr(); - return TIXML_SUCCESS; - } - */ - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char* name, const char * _value ); - - #ifdef TIXML_USE_STL - const std::string* Attribute( const std::string& name ) const; - const std::string* Attribute( const std::string& name, int* i ) const; - const std::string* Attribute( const std::string& name, double* d ) const; - int QueryIntAttribute( const std::string& name, int* _value ) const; - int QueryDoubleAttribute( const std::string& name, double* _value ) const; - - /// STL std::string form. - void SetAttribute( const std::string& name, const std::string& _value ); - ///< STL std::string form. - void SetAttribute( const std::string& name, int _value ); - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char * name, int value ); - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetDoubleAttribute( const char * name, double value ); - - /** Deletes an attribute with the given name. - */ - void RemoveAttribute( const char * name ); - #ifdef TIXML_USE_STL - void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. - #endif - - const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. - TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } - const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. - TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, GetText() is limited compared to getting the TiXmlText child - and accessing it directly. - - If the first child of 'this' is a TiXmlText, the GetText() - returns the character string of the Text node, else null is returned. - - This is a convenient method for getting the text of simple contained text: - @verbatim - This is text - const char* str = fooElement->GetText(); - @endverbatim - - 'str' will be a pointer to "This is text". - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then the value of str would be null. The first child node isn't a text node, it is - another element. From this XML: - @verbatim - This is text - @endverbatim - GetText() will return "This is ". - - WARNING: GetText() accesses a child node - don't become confused with the - similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are - safe type casts on the referenced node. - */ - const char* GetText() const; - - /// Creates a new Element and returns it - the returned element is a copy. - virtual TiXmlNode* Clone() const; - // Print the Element to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: next char past '<' - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - - void CopyTo( TiXmlElement* target ) const; - void ClearThis(); // like clear, but initializes 'this' object as well - - // Used to be public [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - /* [internal use] - Reads the "value" of the element -- another element, or text. - This should terminate with the current end tag. - */ - const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - -private: - - TiXmlAttributeSet attributeSet; -}; - - -/** An XML comment. -*/ -class TINYXML_EXPORT TiXmlComment : public TiXmlNode -{ -public: - /// Constructs an empty comment. - TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} - /// Construct a comment from text. - TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { - SetValue( _value ); - } - TiXmlComment( const TiXmlComment& ); - void operator=( const TiXmlComment& base ); - - virtual ~TiXmlComment() {} - - /// Returns a copy of this Comment. - virtual TiXmlNode* Clone() const; - // Write this Comment to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: at the ! of the !-- - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlComment* target ) const; - - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif -// virtual void StreamOut( TIXML_OSTREAM * out ) const; - -private: - -}; - - -/** XML text. A text node can have 2 ways to output the next. "normal" output - and CDATA. It will default to the mode it was parsed from the XML file and - you generally want to leave it alone, but you can change the output mode with - SetCDATA() and query it with CDATA(). -*/ -class TINYXML_EXPORT TiXmlText : public TiXmlNode -{ - friend class TiXmlElement; -public: - /** Constructor for text element. By default, it is treated as - normal, encoded text. If you want it be output as a CDATA text - element, set the parameter _cdata to 'true' - */ - TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) - { - SetValue( initValue ); - cdata = false; - } - virtual ~TiXmlText() {} - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) - { - SetValue( initValue ); - cdata = false; - } - #endif - - TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } - void operator=( const TiXmlText& base ) { base.CopyTo( this ); } - - // Write this text object to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /// Queries whether this represents text using a CDATA section. - bool CDATA() const { return cdata; } - /// Turns on or off a CDATA representation of text. - void SetCDATA( bool _cdata ) { cdata = _cdata; } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - /// [internal use] Creates a new Element and returns it. - virtual TiXmlNode* Clone() const; - void CopyTo( TiXmlText* target ) const; - - bool Blank() const; // returns true if all white space and new lines - // [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - bool cdata; // true if this should be input and output as a CDATA style text element -}; - - -/** In correct XML the declaration is the first entry in the file. - @verbatim - - @endverbatim - - TinyXml will happily read or write files without a declaration, - however. There are 3 possible attributes to the declaration: - version, encoding, and standalone. - - Note: In this version of the code, the attributes are - handled as special cases, not generic attributes, simply - because there can only be at most 3 and they are always the same. -*/ -class TINYXML_EXPORT TiXmlDeclaration : public TiXmlNode -{ -public: - /// Construct an empty declaration. - TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} - -#ifdef TIXML_USE_STL - /// Constructor. - TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ); -#endif - - /// Construct. - TiXmlDeclaration( const char* _version, - const char* _encoding, - const char* _standalone ); - - TiXmlDeclaration( const TiXmlDeclaration& copy ); - void operator=( const TiXmlDeclaration& copy ); - - virtual ~TiXmlDeclaration() {} - - /// Version. Will return an empty string if none was found. - const char *Version() const { return version.c_str (); } - /// Encoding. Will return an empty string if none was found. - const char *Encoding() const { return encoding.c_str (); } - /// Is this a standalone document? - const char *Standalone() const { return standalone.c_str (); } - - /// Creates a copy of this Declaration and returns it. - virtual TiXmlNode* Clone() const; - // Print this declaration to a FILE stream. - virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlDeclaration* target ) const; - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - - TIXML_STRING version; - TIXML_STRING encoding; - TIXML_STRING standalone; -}; - - -/** Any tag that tinyXml doesn't recognize is saved as an - unknown. It is a tag of text, but should not be modified. - It will be written back to the XML, unchanged, when the file - is saved. - - DTD tags get thrown into TiXmlUnknowns. -*/ -class TINYXML_EXPORT TiXmlUnknown : public TiXmlNode -{ -public: - TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} - virtual ~TiXmlUnknown() {} - - TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } - void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } - - /// Creates a copy of this Unknown and returns it. - virtual TiXmlNode* Clone() const; - // Print this Unknown to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected: - void CopyTo( TiXmlUnknown* target ) const; - - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - -}; - - -/** Always the top level node. A document binds together all the - XML pieces. It can be saved, loaded, and printed to the screen. - The 'value' of a document node is the xml file name. -*/ -class TINYXML_EXPORT TiXmlDocument : public TiXmlNode -{ -public: - /// Create an empty document, that has no name. - TiXmlDocument(); - /// Create a document with a name. The name of the document is also the filename of the xml. - TiXmlDocument( const char * documentName ); - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlDocument( const std::string& documentName ); - #endif - - TiXmlDocument( const TiXmlDocument& copy ); - void operator=( const TiXmlDocument& copy ); - - virtual ~TiXmlDocument() {} - - /** Load a file using the current document value. - Returns true if successful. Will delete any existing - document data before loading. - */ - bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the current document value. Returns true if successful. - bool SaveFile() const; - /// Load a file using the given filename. Returns true if successful. - bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given filename. Returns true if successful. - bool SaveFile( const char * filename ) const; - /** Load a file using the given FILE*. Returns true if successful. Note that this method - doesn't stream - the entire object pointed at by the FILE* - will be interpreted as an XML file. TinyXML doesn't stream in XML from the current - file location. Streaming may be added in the future. - */ - bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given FILE*. Returns true if successful. - bool SaveFile( FILE* ) const; - - #ifdef TIXML_USE_STL - bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. - { -// StringToBuffer f( filename ); -// return ( f.buffer && LoadFile( f.buffer, encoding )); - return LoadFile( filename.c_str(), encoding ); - } - bool SaveFile( const std::string& filename ) const ///< STL std::string version. - { -// StringToBuffer f( filename ); -// return ( f.buffer && SaveFile( f.buffer )); - return SaveFile( filename.c_str() ); - } - #endif - - /** Parse the given null terminated block of xml data. Passing in an encoding to this - method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml - to use that encoding, regardless of what TinyXml might otherwise try to detect. - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - - /** Get the root element -- the only top level element -- of the document. - In well formed XML, there should only be one. TinyXml is tolerant of - multiple elements at the document level. - */ - const TiXmlElement* RootElement() const { return FirstChildElement(); } - TiXmlElement* RootElement() { return FirstChildElement(); } - - /** If an error occurs, Error will be set to true. Also, - - The ErrorId() will contain the integer identifier of the error (not generally useful) - - The ErrorDesc() method will return the name of the error. (very useful) - - The ErrorRow() and ErrorCol() will return the location of the error (if known) - */ - bool Error() const { return error; } - - /// Contains a textual (english) description of the error if one occurs. - const char * ErrorDesc() const { return errorDesc.c_str (); } - - /** Generally, you probably want the error string ( ErrorDesc() ). But if you - prefer the ErrorId, this function will fetch it. - */ - int ErrorId() const { return errorId; } - - /** Returns the location (if known) of the error. The first column is column 1, - and the first row is row 1. A value of 0 means the row and column wasn't applicable - (memory errors, for example, have no row/column) or the parser lost the error. (An - error in the error reporting, in that case.) - - @sa SetTabSize, Row, Column - */ - int ErrorRow() const { return errorLocation.row+1; } - int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() - - /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) - to report the correct values for row and column. It does not change the output - or input in any way. - - By calling this method, with a tab size - greater than 0, the row and column of each node and attribute is stored - when the file is loaded. Very useful for tracking the DOM back in to - the source file. - - The tab size is required for calculating the location of nodes. If not - set, the default of 4 is used. The tabsize is set per document. Setting - the tabsize to 0 disables row/column tracking. - - Note that row and column tracking is not supported when using operator>>. - - The tab size needs to be enabled before the parse or load. Correct usage: - @verbatim - TiXmlDocument doc; - doc.SetTabSize( 8 ); - doc.Load( "myfile.xml" ); - @endverbatim - - @sa Row, Column - */ - void SetTabSize( int _tabsize ) { tabsize = _tabsize; } - - int TabSize() const { return tabsize; } - - /** If you have handled the error, it can be reset with this call. The error - state is automatically cleared if you Parse a new XML block. - */ - void ClearError() { error = false; - errorId = 0; - errorDesc = ""; - errorLocation.row = errorLocation.col = 0; - //errorLocation.last = 0; - } - - /** Write the document to standard out using formatted printing ("pretty print"). */ - void Print() const { Print( stdout, 0 ); } - - /* Write the document to a string using formatted printing ("pretty print"). This - will allocate a character array (new char[]) and return it as a pointer. The - calling code pust call delete[] on the return char* to avoid a memory leak. - */ - //char* PrintToMemory() const; - - /// Print this Document to a FILE stream. - virtual void Print( FILE* cfile, int depth = 0 ) const; - // [internal use] - void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - - virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - // [internal use] - virtual TiXmlNode* Clone() const; - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - void CopyTo( TiXmlDocument* target ) const; - - bool error; - int errorId; - TIXML_STRING errorDesc; - int tabsize; - TiXmlCursor errorLocation; - bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. -}; - - -/** - A TiXmlHandle is a class that wraps a node pointer with null checks; this is - an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml - DOM structure. It is a separate utility class. - - Take an example: - @verbatim - - - - - - - @endverbatim - - Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very - easy to write a *lot* of code that looks like: - - @verbatim - TiXmlElement* root = document.FirstChildElement( "Document" ); - if ( root ) - { - TiXmlElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - TiXmlElement* child = element->FirstChildElement( "Child" ); - if ( child ) - { - TiXmlElement* child2 = child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. - @endverbatim - - And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity - of such code. A TiXmlHandle checks for null pointers so it is perfectly safe - and correct to use: - - @verbatim - TiXmlHandle docHandle( &document ); - TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); - if ( child2 ) - { - // do something useful - @endverbatim - - Which is MUCH more concise and useful. - - It is also safe to copy handles - internally they are nothing more than node pointers. - @verbatim - TiXmlHandle handleCopy = handle; - @endverbatim - - What they should not be used for is iteration: - - @verbatim - int i=0; - while ( true ) - { - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); - if ( !child ) - break; - // do something - ++i; - } - @endverbatim - - It seems reasonable, but it is in fact two embedded while loops. The Child method is - a linear walk to find the element, so this code would iterate much more than it needs - to. Instead, prefer: - - @verbatim - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); - - for( child; child; child=child->NextSiblingElement() ) - { - // do something - } - @endverbatim -*/ -class TINYXML_EXPORT TiXmlHandle -{ -public: - /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. - TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } - /// Copy constructor - TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } - TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } - - /// Return a handle to the first child node. - TiXmlHandle FirstChild() const; - /// Return a handle to the first child node with the given name. - TiXmlHandle FirstChild( const char * value ) const; - /// Return a handle to the first child element. - TiXmlHandle FirstChildElement() const; - /// Return a handle to the first child element with the given name. - TiXmlHandle FirstChildElement( const char * value ) const; - - /** Return a handle to the "index" child with the given name. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( const char* value, int index ) const; - /** Return a handle to the "index" child. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( int index ) const; - /** Return a handle to the "index" child element with the given name. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( const char* value, int index ) const; - /** Return a handle to the "index" child element. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( int index ) const; - - #ifdef TIXML_USE_STL - TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } - TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } - - TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } - TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } - #endif - - /** Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* ToNode() const { return node; } - /** Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } - /** Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } - /** Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } - - /** @deprecated use ToNode. - Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* Node() const { return ToNode(); } - /** @deprecated use ToElement. - Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* Element() const { return ToElement(); } - /** @deprecated use ToText() - Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* Text() const { return ToText(); } - /** @deprecated use ToUnknown() - Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* Unknown() const { return ToUnknown(); } - -private: - TiXmlNode* node; -}; - - -/** Print to memory functionality. The TiXmlPrinter is useful when you need to: - - -# Print to memory (especially in non-STL mode) - -# Control formatting (line endings, etc.) - - When constructed, the TiXmlPrinter is in its default "pretty printing" mode. - Before calling Accept() you can call methods to control the printing - of the XML document. After TiXmlNode::Accept() is called, the printed document can - be accessed via the CStr(), Str(), and Size() methods. - - TiXmlPrinter uses the Visitor API. - @verbatim - TiXmlPrinter printer; - printer.SetIndent( "\t" ); - - doc.Accept( &printer ); - fprintf( stdout, "%s", printer.CStr() ); - @endverbatim -*/ -class TINYXML_EXPORT TiXmlPrinter : public TiXmlVisitor -{ -public: - TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), - buffer(), indent( " " ), lineBreak( "\n" ) {} - - virtual bool VisitEnter( const TiXmlDocument& doc ); - virtual bool VisitExit( const TiXmlDocument& doc ); - - virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); - virtual bool VisitExit( const TiXmlElement& element ); - - virtual bool Visit( const TiXmlDeclaration& declaration ); - virtual bool Visit( const TiXmlText& text ); - virtual bool Visit( const TiXmlComment& comment ); - virtual bool Visit( const TiXmlUnknown& unknown ); - - /** Set the indent characters for printing. By default 4 spaces - but tab (\t) is also useful, or null/empty string for no indentation. - */ - void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } - /// Query the indention string. - const char* Indent() { return indent.c_str(); } - /** Set the line breaking string. By default set to newline (\n). - Some operating systems prefer other characters, or can be - set to the null/empty string for no indenation. - */ - void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } - /// Query the current line breaking string. - const char* LineBreak() { return lineBreak.c_str(); } - - /** Switch over to "stream printing" which is the most dense formatting without - linebreaks. Common when the XML is needed for network transmission. - */ - void SetStreamPrinting() { indent = ""; - lineBreak = ""; - } - /// Return the result. - const char* CStr() { return buffer.c_str(); } - /// Return the length of the result string. - size_t Size() { return buffer.size(); } - - #ifdef TIXML_USE_STL - /// Return the result. - const std::string& Str() { return buffer; } - #endif - -private: - void DoIndent() { - for( int i=0; i -#include - -#include "tinyxml.h" - -//#define DEBUG_PARSER -#if defined( DEBUG_PARSER ) -# if defined( DEBUG ) && defined( _MSC_VER ) -# include -# define TIXML_LOG OutputDebugString -# else -# define TIXML_LOG printf -# endif -#endif - -namespace rospack_tinyxml { - -// Note tha "PutString" hardcodes the same list. This -// is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = -{ - { "&", 5, '&' }, - { "<", 4, '<' }, - { ">", 4, '>' }, - { """, 6, '\"' }, - { "'", 6, '\'' } -}; - -// Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html -// Including the basic of this table, which determines the #bytes in the -// sequence from the lead byte. 1 placed for invalid sequences -- -// although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: -// ef bb bf (Microsoft "lead bytes") -// ef bf be -// ef bf bf - -const unsigned char TIXML_UTF_LEAD_0 = 0xefU; -const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; -const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - -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 -}; - - -void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) -{ - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) - *length = 1; - else if ( input < 0x800 ) - *length = 2; - else if ( input < 0x10000 ) - *length = 3; - else if ( input < 0x200000 ) - *length = 4; - else - { *length = 0; return; } // This code won't covert this correctly anyway. - - output += *length; - - // Scary scary fall throughs. - switch (*length) - { - case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 1: - --output; - *output = (char)(input | FIRST_BYTE_MARK[*length]); - } -} - - -/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalpha( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalpha( anyByte ); -// } -} - - -/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalnum( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalnum( anyByte ); -// } -} - - -class TiXmlParsingData -{ - friend class TiXmlDocument; - public: - void Stamp( const char* now, TiXmlEncoding encoding ); - - const TiXmlCursor& Cursor() { return cursor; } - - private: - // Only used by the document! - TiXmlParsingData( const char* start, int _tabsize, int row, int col ) - { - assert( start ); - stamp = start; - tabsize = _tabsize; - cursor.row = row; - cursor.col = col; - } - - TiXmlCursor cursor; - const char* stamp; - int tabsize; -}; - - -void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) -{ - assert( now ); - - // Do nothing if the tabsize is 0. - if ( tabsize < 1 ) - { - return; - } - - // Get the current row, column. - int row = cursor.row; - int col = cursor.col; - const char* p = stamp; - assert( p ); - - while ( p < now ) - { - // Treat p as unsigned, so we have a happy compiler. - const unsigned char* pU = (const unsigned char*)p; - - // Code contributed by Fletcher Dunn: (modified by lee) - switch (*pU) { - case 0: - // We *should* never get here, but in case we do, don't - // advance past the terminating null character, ever - return; - - case '\r': - // bump down to the next line - ++row; - col = 0; - // Eat the character - ++p; - - // Check for \r\n sequence, and treat this as a single character - if (*p == '\n') { - ++p; - } - break; - - case '\n': - // bump down to the next line - ++row; - col = 0; - - // Eat the character - ++p; - - // Check for \n\r sequence, and treat this as a single - // character. (Yes, this bizarre thing does occur still - // on some arcane platforms...) - if (*p == '\r') { - ++p; - } - break; - - case '\t': - // Eat the character - ++p; - - // Skip to next tab stop - col = (col / tabsize + 1) * tabsize; - break; - - case TIXML_UTF_LEAD_0: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( *(p+1) && *(p+2) ) - { - // In these cases, don't advance the column. These are - // 0-width spaces. - if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) - p += 3; - else - { p +=3; ++col; } // A normal character. - } - } - else - { - ++p; - ++col; - } - break; - - default: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // Eat the 1 to 4 byte utf8 character. - int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; - if ( step == 0 ) - step = 1; // Error case from bad encoding, but handle gracefully. - p += step; - - // Just advance one column, of course. - ++col; - } - else - { - ++p; - ++col; - } - break; - } - } - cursor.row = row; - cursor.col = col; - assert( cursor.row >= -1 ); - assert( cursor.col >= -1 ); - stamp = p; - assert( stamp ); -} - - -const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) -{ - if ( !p || !*p ) - { - return 0; - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - while ( *p ) - { - const unsigned char* pU = (const unsigned char*)p; - - // Skip the stupid Microsoft UTF-8 Byte order marks - if ( *(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==TIXML_UTF_LEAD_1 - && *(pU+2)==TIXML_UTF_LEAD_2 ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbeU ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbfU ) - { - p += 3; - continue; - } - - if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. - ++p; - else - break; - } - } - else - { - while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) - ++p; - } - - return p; -} - -#ifdef TIXML_USE_STL -/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) -{ - for( ;; ) - { - if ( !in->good() ) return false; - - int c = in->peek(); - // At this scope, we can't get to a document. So fail silently. - if ( !IsWhiteSpace( c ) || c <= 0 ) - return true; - - *tag += (char) in->get(); - } -} - -/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) -{ - //assert( character > 0 && character < 128 ); // else it won't work in utf-8 - while ( in->good() ) - { - int c = in->peek(); - if ( c == character ) - return true; - if ( c <= 0 ) // Silent failure: can't get document at this scope - return false; - - in->get(); - *tag += (char) c; - } - return false; -} -#endif - -// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The -// "assign" optimization removes over 10% of the execution time. -// -const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) -{ - // Oddly, not supported on some comilers, - //name->clear(); - // So use this: - *name = ""; - assert( p ); - - // Names start with letters or underscores. - // Of course, in unicode, tinyxml has no idea what a letter *is*. The - // algorithm is generous. - // - // After that, they can be letters, underscores, numbers, - // hyphens, or colons. (Colons are valid ony for namespaces, - // but tinyxml can't tell namespaces from names.) - if ( p && *p - && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) - { - const char* start = p; - while( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) - || *p == '_' - || *p == '-' - || *p == '.' - || *p == ':' ) ) - { - //(*name) += *p; // expensive - ++p; - } - if ( p-start > 0 ) { - name->assign( start, p-start ); - } - return p; - } - return 0; -} - -const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) -{ - // Presume an entity, and pull it out. - TIXML_STRING ent; - int i; - *length = 0; - - if ( *(p+1) && *(p+1) == '#' && *(p+2) ) - { - unsigned long ucs = 0; - ptrdiff_t delta = 0; - unsigned mult = 1; - - if ( *(p+2) == 'x' ) - { - // Hexadecimal. - if ( !*(p+3) ) return 0; - - const char* q = p+3; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != 'x' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else if ( *q >= 'a' && *q <= 'f' ) - ucs += mult * (*q - 'a' + 10); - else if ( *q >= 'A' && *q <= 'F' ) - ucs += mult * (*q - 'A' + 10 ); - else - return 0; - mult *= 16; - --q; - } - } - else - { - // Decimal. - if ( !*(p+2) ) return 0; - - const char* q = p+2; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != '#' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else - return 0; - mult *= 10; - --q; - } - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8( ucs, value, length ); - } - else - { - *value = (char)ucs; - *length = 1; - } - return p + delta + 1; - } - - // Now try to match it. - for( i=0; iappend( cArr, len ); - } - } - else - { - bool whitespace = false; - - // Remove leading white space: - p = SkipWhiteSpace( p, encoding ); - while ( p && *p - && !StringEqual( p, endTag, caseInsensitive, encoding ) ) - { - if ( *p == '\r' || *p == '\n' ) - { - whitespace = true; - ++p; - } - else if ( IsWhiteSpace( *p ) ) - { - whitespace = true; - ++p; - } - else - { - // If we've found whitespace, add it before the - // new character. Any whitespace just becomes a space. - if ( whitespace ) - { - (*text) += ' '; - whitespace = false; - } - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar( p, cArr, &len, encoding ); - if ( len == 1 ) - (*text) += cArr[0]; // more efficient - else - text->append( cArr, len ); - } - } - } - if ( p ) - p += strlen( endTag ); - return p; -} - -#ifdef TIXML_USE_STL - -void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - // The basic issue with a document is that we don't know what we're - // streaming. Read something presumed to be a tag (and hope), then - // identify it, and call the appropriate stream method on the tag. - // - // This "pre-streaming" will never read the closing ">" so the - // sub-tag can orient itself. - - if ( !StreamTo( in, '<', tag ) ) - { - SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - while ( in->good() ) - { - int tagIndex = (int) tag->length(); - while ( in->good() && in->peek() != '>' ) - { - int c = in->get(); - if ( c <= 0 ) - { - SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - break; - } - (*tag) += (char) c; - } - - if ( in->good() ) - { - // We now have something we presume to be a node of - // some sort. Identify it, and call the node to - // continue streaming. - TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); - - if ( node ) - { - node->StreamIn( in, tag ); - bool isElement = node->ToElement() != 0; - delete node; - node = 0; - - // If this is the root element, we're done. Parsing will be - // done by the >> operator. - if ( isElement ) - { - return; - } - } - else - { - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - } - } - // We should have returned sooner. - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); -} - -#endif - -const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) -{ - ClearError(); - - // Parse away, at the document level. Since a document - // contains nothing but other tags, most of what happens - // here is skipping white space. - if ( !p || !*p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - // Note that, for a document, this needs to come - // before the while space skip, so that parsing - // starts from the pointer we are given. - location.Clear(); - if ( prevData ) - { - location.row = prevData->cursor.row; - location.col = prevData->cursor.col; - } - else - { - location.row = 0; - location.col = 0; - } - TiXmlParsingData data( p, TabSize(), location.row, location.col ); - location = data.Cursor(); - - if ( encoding == TIXML_ENCODING_UNKNOWN ) - { - // Check for the Microsoft UTF-8 lead bytes. - const unsigned char* pU = (const unsigned char*)p; - if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 - && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 - && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) - { - encoding = TIXML_ENCODING_UTF8; - useMicrosoftBOM = true; - } - } - - p = SkipWhiteSpace( p, encoding ); - if ( !p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - while ( p && *p ) - { - TiXmlNode* node = Identify( p, encoding ); - if ( node ) - { - p = node->Parse( p, &data, encoding ); - LinkEndChild( node ); - } - else - { - break; - } - - // Did we get encoding info? - if ( encoding == TIXML_ENCODING_UNKNOWN - && node->ToDeclaration() ) - { - TiXmlDeclaration* dec = node->ToDeclaration(); - const char* enc = dec->Encoding(); - assert( enc ); - - if ( *enc == 0 ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else - encoding = TIXML_ENCODING_LEGACY; - } - - p = SkipWhiteSpace( p, encoding ); - } - - // Was this empty? - if ( !firstChild ) { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); - return 0; - } - - // All is well. - return p; -} - -void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - // The first error in a chain is more accurate - don't set again! - if ( error ) - return; - - assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); - error = true; - errorId = err; - errorDesc = errorString[ errorId ]; - - errorLocation.Clear(); - if ( pError && data ) - { - data->Stamp( pError, encoding ); - errorLocation = data->Cursor(); - } -} - - -TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) -{ - TiXmlNode* returnNode = 0; - - p = SkipWhiteSpace( p, encoding ); - if( !p || !*p || *p != '<' ) - { - return 0; - } - - TiXmlDocument* doc = GetDocument(); - p = SkipWhiteSpace( p, encoding ); - - if ( !p || !*p ) - { - return 0; - } - - // What is this thing? - // - Elements start with a letter or underscore, but xml is reserved. - // - Comments: "; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // [ 1475201 ] TinyXML parses entities in comments - // Oops - ReadText doesn't work, because we don't want to parse the entities. - // p = ReadText( p, &value, false, endTag, false, encoding ); - // - // from the XML spec: - /* - [Definition: Comments may appear anywhere in a document outside other markup; in addition, - they may appear within the document type declaration at places allowed by the grammar. - They are not part of the document's character data; an XML processor MAY, but need not, - make it possible for an application to retrieve the text of comments. For compatibility, - the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity - references MUST NOT be recognized within comments. - - An example of a comment: - - - */ - - value = ""; - // Keep all the white space. - while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) - { - value.append( p, 1 ); - ++p; - } - if ( p ) - p += strlen( endTag ); - - return p; -} - - -const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) return 0; - -// int tabsize = 4; -// if ( document ) -// tabsize = document->TabSize(); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - // Read the name, the '=' and the value. - const char* pErr = p; - p = ReadName( p, &name, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); - return 0; - } - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p || *p != '=' ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - ++p; // skip '=' - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - const char* end; - const char SINGLE_QUOTE = '\''; - const char DOUBLE_QUOTE = '\"'; - - if ( *p == SINGLE_QUOTE ) - { - ++p; - end = "\'"; // single quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else if ( *p == DOUBLE_QUOTE ) - { - ++p; - end = "\""; // double quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else - { - // All attribute values should be in single or double quotes. - // But this is such a common error that the parser will try - // its best, even without them. - value = ""; - while ( p && *p // existence - && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace - && *p != '/' && *p != '>' ) // tag end - { - if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { - // [ 1451649 ] Attribute values with trailing quotes not handled correctly - // We did not have an opening quote but seem to have a - // closing one. Give up and throw an error. - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - value += *p; - ++p; - } - } - return p; -} - -#ifdef TIXML_USE_STL -void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->peek(); - if ( !cdata && (c == '<' ) ) - { - return; - } - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - (*tag) += (char) c; - in->get(); // "commits" the peek made above - - if ( cdata && c == '>' && tag->size() >= 3 ) { - size_t len = tag->size(); - if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { - // terminator of cdata. - return; - } - } - } -} -#endif - -const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - value = ""; - TiXmlDocument* document = GetDocument(); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - - const char* const startTag = ""; - - if ( cdata || StringEqual( p, startTag, false, encoding ) ) - { - cdata = true; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // Keep all the white space, ignore the encoding, etc. - while ( p && *p - && !StringEqual( p, endTag, false, encoding ) - ) - { - value += *p; - ++p; - } - - TIXML_STRING dummy; - p = ReadText( p, &dummy, false, endTag, false, encoding ); - return p; - } - else - { - bool ignoreWhite = true; - - const char* end = "<"; - p = ReadText( p, &value, ignoreWhite, end, false, encoding ); - if ( p ) - return p-1; // don't truncate the '<' - return 0; - } -} - -#ifdef TIXML_USE_STL -void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - (*tag) += (char) c; - - if ( c == '>' ) - { - // All is well. - return; - } - } -} -#endif - -const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) -{ - p = SkipWhiteSpace( p, _encoding ); - // Find the beginning, find the end, and look for - // the stuff in-between. - TiXmlDocument* document = GetDocument(); - if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); - return 0; - } - if ( data ) - { - data->Stamp( p, _encoding ); - location = data->Cursor(); - } - p += 5; - - version = ""; - encoding = ""; - standalone = ""; - - while ( p && *p ) - { - if ( *p == '>' ) - { - ++p; - return p; - } - - p = SkipWhiteSpace( p, _encoding ); - if ( StringEqual( p, "version", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - version = attrib.Value(); - } - else if ( StringEqual( p, "encoding", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - encoding = attrib.Value(); - } - else if ( StringEqual( p, "standalone", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - standalone = attrib.Value(); - } - else - { - // Read over whatever it is. - while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) - ++p; - } - } - return 0; -} - -bool TiXmlText::Blank() const -{ - for ( unsigned i=0; i