From 798ce9fb0a99a12935531f8a62efaeaa9fd469b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 5 Mar 2010 00:55:57 +0100 Subject: [PATCH] CR-LF mess --- Compile.txt | 138 --- Readme.txt | 174 ---- library/argstream/argstream.h | 1630 ++++++++++++++++----------------- 3 files changed, 815 insertions(+), 1127 deletions(-) delete mode 100644 Compile.txt delete mode 100644 Readme.txt diff --git a/Compile.txt b/Compile.txt deleted file mode 100644 index 92e0164ef..000000000 --- a/Compile.txt +++ /dev/null @@ -1,138 +0,0 @@ -Here's how you build dfhack! ----------------------------- - -First, there is one dependency, regardless of the OS you use: - cmake - it's the build system - - -Building on Linux: --------------------- - -* To run in the output folder (without installing): - -building the library is simple. Enter the build folder, run the tools. Like this: - -cd build -cmake .. -DCMAKE_BUILD_TYPE:string=Release -make - -This will build the library and its tools and place them in /output. -You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI program. - -* To be installed into the system or packaged - -cd build -cmake -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/usr -DMEMXML_DATA_PATH:path=/usr/share/dfhack .. -make -make install - -With this dfhack installs: -library to $CMAKE_INSTALL_PREFIX/lib -executables to $CMAKE_INSTALL_PREFIX/bin -The Memory.xml file to /usr/share/dfhack - -See the section on the shared memory hook library (SHM). - -Building on Windows: --------------------- - -You need cmake. Get the win32 installer version from the official site: http://www.cmake.org/cmake/resources/software.html -It has the usual installer wizard thing. - -* Using mingw: - -You also need a compiler. I build dfhack using mingw. You can get it from the mingw site: -Get the automated installer, it will download newest version of mingw and set things up nicely. -You'll have to add C:\MinGW\ to your PATH variable. - - - Building: - open up cmd and navigate to the dfhack\build folder, run cmake and the mingw version of make: - cd build - cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release - mingw32-make - -* Using MSVC - -open up cmd and navigate to the dfhack\build folder, run cmake: -cd build -cmake .. - -This will generate MSVC solution and project files. Note that: you are working in the /build folder. -Files added to projects will end up there! (and that's wrong). Any changes to the build system should -be done by changing cmake configs and running cmake on them! - -* Using some other compiler: - -I'm afraid you are on your own. dfhack wasn't tested with any other compiler. -Try using a different cmake generator that's intended for your tools. - - -Building the shared memory hook library (SHM) ---------------------------------------------- - -Unlike the rest of DFHack, The SHM needs special treatment when it comes to compilation. -Because it shares the memory space with DF itself, it has to be built with the same tools as DF -and use the same C and C++/STL libraries. - -For DF 40d15 - 40d17 on Windows, use MSVC 2008. You can get the Express edition for free from Microsoft. - -Windows dependencies can be determined by a tool like depends.exe (google it). Both the fake SDL.dll -and DF have to use the same version of the C runtime (MSVCRT). -The SHM can't be debugged, because debug builds in MSVC use a different CRT! - -Linux dependencies can be determined by setting the LD_DEBUG variable and running ./df: -export LD_DEBUG=versions -./df - -Example of (a part of a) relevant output from a working SHM installation: - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libpthread.so.0 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GCC_3.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.1' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBCXX_3.4.9' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.2' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - -libdfconnect is the SHM. Both are compiled against the same C++ library and share the same CXXABI version. - -Precompiled SHM libraries are provided in binary releases. - -* Checking strings support - -Strings are one of the important C++ types and a great indicator that the SHM works. Tools like Dwarf Therapist depend -on string support. Reading of strings can be checked by running any of the tools that deal with materials. - -String writing is best tested with a fresh throw-away fort and dfrenamer. Embark, give one dwarf a very long name using dfrenamer -and save/exit. If DF crashes during the save sequence, your SHM is not compatible with DF and the throw-away fort is lost. - - -Build targets -------------- - -dfhack has a few build targets. If you're only after the library run 'make dfhack'. -'make' will build everything. -'make expbench' will build the expbench throughput testing program and the library. - - -Build types ------------ - -cmake allows you to pick a build type by changing this variable: CMAKE_BUILD_TYPE - -cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE - -Without specifying a build type or 'None', cmake uses the CMAKE_CXX_FLAGS variable for building. -Valid build types include 'Release' and 'Debug'. There are others, but they aren't really that useful. - -Have fun. diff --git a/Readme.txt b/Readme.txt deleted file mode 100644 index 8600bc63b..000000000 --- a/Readme.txt +++ /dev/null @@ -1,174 +0,0 @@ -Introduction ------------- - -DFHack is a Dwarf Fortress memory access library and a set of basic tools using -this library. The library is a work in progress, so things might change as more -tools are written for it. - -It is an attempt to unite the various ways tools access DF memory and allow for -easier development of new tools. - - -Getting DFHack ----------------- -The project is currently hosted on github: - http://github.com/peterix/dfhack - -There's an SVN repository at sourceforge, but will only be updated for major releases: - https://sourceforge.net/projects/dfhack/ -* subversion access: - svn co https://dfhack.svn.sourceforge.net/svnroot/dfhack/trunk dfhack - -Compatibility -------------- - -DFHack works on Windows XP, Vista, 7 or any modern Linux distribution. - -Windows 2000 is currently *not supported* due to missing OS functionality. -If you know how to easily suspend processes, you can fix it :) - -OSX is also not supported due to lack of developers with a Mac. - -Currently supported Dwarf Fortress versions: -* Windows - 40d - 40d9 - 40d18 - -* Linux - 40d9 - 40d18 - - -Using the library ------------------ - -The library is compilable under Linux with GCC and under Windows with MinGW32 -and MSVC compilers. It is using the cmake build system. See COMPILE for details. - -DFHack is using the zlib/libpng license. This makes it easy to link to it, use -it in-source or add your own extensions. Contributing back to the dfhack -repository is welcome and the right thing to do :) - -At the time of writing there's no API reference or documentation. The code does -have a lot of comments though. - - -Using DFHack Tools ------------------- - -The project comes with a special extra library you should add to your DF -installation. It's used to boost the transfer speed between DF and DFHack, and -provide data consistency and synchronization. DFHack will work without the -library, but at suboptimal speeds and the consistency of data written back -to DF is questionable. - -!!! on Windows this currently only works with DF 40d15 - 40d18 !!! - On Linux, it works with the whole range of supported DF versions. - -!!! use the pre-compiled library intended for your OS and version of DF !!! - You can find them in the 'precompiled' folder. - - - ** Installing on Windows - - Open your DF folder, locate SDL.dll and rename it to SDLreal.dll (making - a backup of it is a good idea) - - Copy the right DFHack SDL.dll into your DF folder. - - Restart DF if it is running - - ** Unistalling on Windows - - Open your DF folder, locate SDL.dll and delete it - - Rename SDLreal.dll to SDL.dll - - Restart DF if it is running - - - ** Installing on Linux - - Open your DF folder and the libs folder within it - - copy DFHack libdfconnect.so to the libs folder - - copy the df startup script, name it dfhacked - - open the new dfhacked startup script and add this line: - export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF! - just before the line that launches DF - - Here's an example how the file can look after the change: -#!/bin/sh -DF_DIR=$(dirname "$0") -cd "${DF_DIR}" -export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch. -#export SDL_VIDEO_CENTERED=1 # Centre the screen. Messes up resizing. -ldd dwarfort.exe | grep SDL_image | grep -qv "not found$" -if [ $? -eq 0 ]; then - mkdir unused_libs - mv libs/libSDL* unused_libs/ -fi -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"./libs" # Update library search path. -export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF! -./dwarfort.exe $* # Go, go, go! :) - - - Use this new startup script to start DF - - ** Uninstalling on Linux - - Open your DF and DF/libs folders - - Delete libdfconnect.so and the dfhacked startup script - - Go back to using the df startup script - - -Tools ------ - -All the DFHack tools are terminal programs. This might seem strange to Windows -users, but these are meant mostly as examples for developers. Still, they can -be useful and are cross-platform just like the library itself. - -If the tool writes back to DF's memory, make sure you are using the shared -memory interface mentioned in the previous section! - -* reveal - plain old reveal tool. It reveals all the map blocks already - initialized by DF. - -* prospector - scans the map for minerals. by default it only scans only visible - veins. You can make it show hidden things with '-a' and base rock - and soil layers with '-b'. These can be combined ('-ab') - -* cleanmap - cleans mud, vomit, snow and all kinds of mess from the map. - It will clean your irrigated farms too, so consider yourself - warned. - -* incremental - incremental search utility. - -* bauxite - converts all mechanisms into bauxite mechanisms. - -* itemdesignator - Allows mass-designating items by type and material - dump, - forbid, melt and set on fire ;) -* digger - allows designating tiles for digging/cutting/ramp removal - - A list of accepted tile classes: - 1 = WALL - 2 = PILLAR - 3 = FORTIFICATION - - 4 = STAIR_UP - 5 = STAIR_DOWN - 6 = STAIR_UPDOWN - - 7 = RAMP - - 8 = FLOOR - 9 = TREE_DEAD - 10 = TREE_OK - 11 = SAPLING_DEAD - 12 = SAPLING_OK - 13 = SHRUB_DEAD - 14 = SHRUB_OK - 15 = BOULDER - 16 = PEBBLES - - Example : dfdigger -o 100,100,15 -t 9,10 -m 10 - This will start looking for trees at coords 100,100,15 and designate ten of them for cutting. - - -Memory offset definitions -------------------------- - -The file with memory offset definitions used by dfhack can be found in the -output folder. - -~ EOF ~ diff --git a/library/argstream/argstream.h b/library/argstream/argstream.h index cdc8e4600..9e2761493 100644 --- a/library/argstream/argstream.h +++ b/library/argstream/argstream.h @@ -1,815 +1,815 @@ -/* Copyright (C) 2004 Xavier Décoret -* -* argsteam is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* Foobar is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Foobar; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef ARGSTREAM_H -#define ARGSTREAM_H - - -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - class argstream; - - template - class ValueHolder; - - template - argstream& operator>> (argstream&, const ValueHolder&); - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValueHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValueHolder - { - public: - ValueHolder(char s, - const char* l, - T& b, - const char* desc, - bool mandatory); - ValueHolder(const char* l, - T& b, - const char* desc, - bool mandatory); - ValueHolder(char s, - T& b, - const char* desc, - bool mandatory); - friend argstream& operator>><>(argstream& s,const ValueHolder& v); - std::string name() const; - std::string description() const; - private: - std::string shortName_; - std::string longName_; - T* value_; - T initialValue_; - std::string description_; - bool mandatory_; - }; - template - inline ValueHolder - parameter(char s, - const char* l, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(s,l,b,desc,mandatory); - } - template - inline ValueHolder - parameter(char s, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(s,b,desc,mandatory); - } - template - inline ValueHolder - parameter(const char* l, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(l,b,desc,mandatory); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of OptionHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - class OptionHolder - { - public: - inline OptionHolder(char s, - const char* l, - bool& b, - const char* desc); - inline OptionHolder(const char* l, - bool& b, - const char* desc); - inline OptionHolder(char s, - bool& b, - const char* desc); - friend argstream& operator>>(argstream& s,const OptionHolder& v); - inline std::string name() const; - inline std::string description() const; - protected: - inline OptionHolder(char s, - const char* l, - const char* desc); - friend OptionHolder help(char s='h', - const char* l="help", - const char* desc="Display this help"); - private: - std::string shortName_; - std::string longName_; - bool* value_; - std::string description_; - }; - inline OptionHolder - option(char s, - const char* l, - bool& b, - const char* desc="") - { - return OptionHolder(s,l,b,desc); - } - inline OptionHolder - option(char s, - bool& b, - const char* desc="") - { - return OptionHolder(s,b,desc); - } - inline OptionHolder - option(const char* l, - bool& b, - const char* desc="") - { - return OptionHolder(l,b,desc); - } - inline OptionHolder - help(char s, - const char* l, - const char* desc) - { - return OptionHolder(s,l,desc); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValuesHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValuesHolder - { - public: - ValuesHolder(const O& o, - const char* desc, - int len); - friend argstream& operator>><>(argstream& s,const ValuesHolder& v); - std::string name() const; - std::string description() const; - typedef T value_type; - private: - mutable O value_; - std::string description_; - int len_; - char letter_; - }; - template - inline ValuesHolder - values(const O& o, - const char* desc="", - int len=-1) - { - return ValuesHolder(o,desc,len); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValueParser - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValueParser - { - public: - inline T operator()(const std::string& s) const - { - std::istringstream is(s); - T t; - is>>t; - return t; - } - }; - // We need to specialize for string otherwise parsing of a value that - // contains space (for example a string with space passed in quotes on the - // command line) would parse only the first element of the value!!! - template <> - class ValueParser - { - public: - inline std::string operator()(const std::string& s) const - { - return s; - } - }; - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of argstream - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - class argstream - { - public: - inline argstream(int argc,char** argv); - //inline argstream(const char* c); - template - friend argstream& operator>>(argstream& s,const ValueHolder& v); - friend inline argstream& operator>>(argstream& s,const OptionHolder& v); - template - friend argstream& operator>>(argstream& s,const ValuesHolder& v); - - inline bool helpRequested() const; - inline bool isOk() const; - inline std::string errorLog() const; - inline std::string usage() const; - inline void defaultErrorHandling(bool ignoreUnused=false) const; - static inline char uniqueLetter(); - protected: - void parse(int argc,char** argv); - private: - typedef std::list::iterator value_iterator; - typedef std::pair help_entry; - std::string progName_; - std::map options_; - std::list values_; - bool minusActive_; - bool isOk_; - std::deque argHelps_; - std::string cmdLine_; - std::deque errors_; - bool helpRequested_; - }; - //************************************************************ - // Implementation of ValueHolder - //************************************************************ - template - ValueHolder::ValueHolder(char s, - const char* l, - T& v, - const char* desc, - bool mandatory) - : shortName_(1,s), - longName_(l), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - ValueHolder::ValueHolder(const char* l, - T& v, - const char* desc, - bool mandatory) - : longName_(l), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - ValueHolder::ValueHolder(char s, - T& v, - const char* desc, - bool mandatory) - : shortName_(1,s), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - std::string - ValueHolder::name() const - { - std::ostringstream os; - if (!shortName_.empty()) os<<'-'< - std::string - ValueHolder::description() const - { - std::ostringstream os; - os< - //************************************************************ - template - ValuesHolder::ValuesHolder(const O& o, - const char* desc, - int len) - : value_(o), - description_(desc), - len_(len) - { - letter_ = argstream::uniqueLetter(); - } - template - std::string - ValuesHolder::name() const - { - std::ostringstream os; - os< - std::string - ValuesHolder::description() const - { - return description_; - } - //************************************************************ - // Implementation of argstream - //************************************************************ - inline - argstream::argstream(int argc,char** argv) - : progName_(argv[0]), - minusActive_(true), - isOk_(true) - { - parse(argc,argv); - } - //inline - // argstream::argstream(const char* c) - // : progName_(""), - // minusActive_(true), - // isOk_(true) - //{ - // std::string s(c); - // // Build argc, argv from s. We must add a dummy first element for - // // progName because parse() expects it!! - // std::deque args; - // args.push_back(""); - // std::istringstream is(s); - // while (is.good()) - // { - // std::string t; - // is>>t; - // args.push_back(t); - // } - // char* pargs[args.size()]; - // char** p = pargs; - // for (std::deque::const_iterator - // iter = args.begin(); - // iter != args.end();++iter) - // { - // *p++ = const_cast(iter->c_str()); - // } - // parse(args.size(),pargs); - //} - inline void - argstream::parse(int argc,char** argv) - { - // Run thru all arguments. - // * it has -- in front : it is a long name option, if remainder is empty, - // it is an error - // * it has - in front : it is a sequence of short name options, if - // remainder is empty, deactivates option (- will - // now be considered a char). - // * if any other char, or if option was deactivated - // : it is a value. Values are split in parameters - // (immediately follow an option) and pure values. - // Each time a value is parsed, if the previously parsed argument was an - // option, then the option is linked to the value in case of it is a - // option with parameter. The subtle point is that when several options - // are given with short names (ex: -abc equivalent to -a -b -c), the last - // parsed option is -c). - // Since we use map for option, any successive call overides the previous - // one: foo -a -b -a hello is equivalent to foo -b -a hello - // For values it is not true since we might have several times the same - // value. - value_iterator* lastOption = NULL; - for (char** a = argv,**astop=a+argc;++a!=astop;) - { - std::string s(*a); - if (minusActive_ && s[0] == '-') - { - if (s.size() > 1 && s[1] == '-') - { - if (s.size() == 2) - { - minusActive_ = false; - continue; - } - lastOption = &(options_[s.substr(2)] = values_.end()); - } - else - { - if (s.size() > 1) - { - // Parse all chars, if it is a minus we have an error - for (std::string::const_iterator cter = s.begin(); - ++cter != s.end();) - { - if (*cter == '-') - { - isOk_ = false; - std::ostringstream os; - os<<"- in the middle of a switch "<::const_iterator - iter = options_.begin();iter != options_.end();++iter) - { - std::cout<<"DEBUG: option "<first; - if (iter->second != values_.end()) - { - std::cout<<" -> "<<*(iter->second); - } - std::cout<::const_iterator - iter = values_.begin();iter != values_.end();++iter) - { - std::cout<<"DEBUG: value "<<*iter<::const_iterator - iter = argHelps_.begin();iter != argHelps_.end();++iter) - { - if (lmaxfirst.size()) lmax = iter->first.size(); - } - for (std::deque::const_iterator - iter = argHelps_.begin();iter != argHelps_.end();++iter) - { - os<<'\t'<first<first.size(),' ') - <<" : "<second<<'\n'; - } - return os.str(); - } - inline std::string - argstream::errorLog() const - { - std::string s; - for(std::deque::const_iterator iter = errors_.begin(); - iter != errors_.end();++iter) - { - s += *iter; - s += '\n'; - } - return s; - } - inline char - argstream::uniqueLetter() - { - static unsigned int c = 'a'; - return c++; - } - template - argstream& - operator>>(argstream& s,const ValueHolder& v) - { - // Search in the options if there is any such option defined either with a - // short name or a long name. If both are found, only the last one is - // used. -#ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: searching "<::iterator iter = - s.options_.find(v.shortName_); - if (iter == s.options_.end()) - { - iter = s.options_.find(v.longName_); - } - if (iter != s.options_.end()) - { - // If we find counterpart for value holder on command line, either it - // has an associated value in which case we assign it, or it has not, in - // which case we have an error. - if (iter->second != s.values_.end()) - { -#ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: found value "<<*(iter->second)< p; - *(v.value_) = p(*(iter->second)); - // The option and its associated value are removed, the subtle thing - // is that someother options might have this associated value too, - // which we must invalidate. - s.values_.erase(iter->second); - - // FIXME this loop seems to crash if a std::string is used as the value - //for (std::map::iterator - // jter = s.options_.begin();jter != s.options_.end();++jter) - //{ - // if (jter->second == iter->second) - // { - // jter->second = s.values_.end(); - // } - //} - s.options_.erase(iter); - } - else - { - s.isOk_ = false; - std::ostringstream os; - os<<"No value following switch "<first - <<" on command line"; - s.errors_.push_back(os.str()); - } - } - else - { - if (v.mandatory_) - { - s.isOk_ = false; - std::ostringstream os; - os<<"Mandatory parameter "; - if (!v.shortName_.empty()) os<<'-'<>(argstream& s,const OptionHolder& v) - { - // Search in the options if there is any such option defined either with a - // short name or a long name. If both are found, only the last one is - // used. -#ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: searching "<::iterator iter = - s.options_.find(v.shortName_); - if (iter == s.options_.end()) - { - iter = s.options_.find(v.longName_); - } - if (iter != s.options_.end()) - { - // If we find counterpart for value holder on command line then the - // option is true and if an associated value was found, it is ignored - if (v.value_ != NULL) - { - *(v.value_) = true; - } - else - { - s.helpRequested_ = true; - } - // The option only is removed - s.options_.erase(iter); - } - else - { - if (v.value_ != NULL) - { - *(v.value_) = false; - } - else - { - s.helpRequested_ = false; - } - } - return s; - } - template - argstream& - operator>>(argstream& s,const ValuesHolder& v) - { - s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); - { - std::ostringstream os; - os<<' '<::iterator first = s.values_.begin(); - // We add to the iterator as much values as we can, limited to the length - // specified (if different of -1) - int n = v.len_ != -1?v.len_:s.values_.size(); - while (first != s.values_.end() && n-->0) - { - // Read the value from the string *first - ValueParser p; - *(v.value_++) = p(*first ); - s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); - // The value we just removed was maybe "remembered" by an option so we - // remove it now. - for (std::map::iterator - jter = s.options_.begin();jter != s.options_.end();++jter) - { - if (jter->second == first) - { - jter->second = s.values_.end(); - } - } - ++first; - } - // Check if we have enough values - if (n != 0) - { - s.isOk_ = false; - std::ostringstream os; - os<<"Expecting "< +* +* argsteam is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* Foobar is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Foobar; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef ARGSTREAM_H +#define ARGSTREAM_H + + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + class argstream; + + template + class ValueHolder; + + template + argstream& operator>> (argstream&, const ValueHolder&); + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueHolder + { + public: + ValueHolder(char s, + const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(char s, + T& b, + const char* desc, + bool mandatory); + friend argstream& operator>><>(argstream& s,const ValueHolder& v); + std::string name() const; + std::string description() const; + private: + std::string shortName_; + std::string longName_; + T* value_; + T initialValue_; + std::string description_; + bool mandatory_; + }; + template + inline ValueHolder + parameter(char s, + const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,l,b,desc,mandatory); + } + template + inline ValueHolder + parameter(char s, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,b,desc,mandatory); + } + template + inline ValueHolder + parameter(const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(l,b,desc,mandatory); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of OptionHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class OptionHolder + { + public: + inline OptionHolder(char s, + const char* l, + bool& b, + const char* desc); + inline OptionHolder(const char* l, + bool& b, + const char* desc); + inline OptionHolder(char s, + bool& b, + const char* desc); + friend argstream& operator>>(argstream& s,const OptionHolder& v); + inline std::string name() const; + inline std::string description() const; + protected: + inline OptionHolder(char s, + const char* l, + const char* desc); + friend OptionHolder help(char s='h', + const char* l="help", + const char* desc="Display this help"); + private: + std::string shortName_; + std::string longName_; + bool* value_; + std::string description_; + }; + inline OptionHolder + option(char s, + const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(s,l,b,desc); + } + inline OptionHolder + option(char s, + bool& b, + const char* desc="") + { + return OptionHolder(s,b,desc); + } + inline OptionHolder + option(const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(l,b,desc); + } + inline OptionHolder + help(char s, + const char* l, + const char* desc) + { + return OptionHolder(s,l,desc); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValuesHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValuesHolder + { + public: + ValuesHolder(const O& o, + const char* desc, + int len); + friend argstream& operator>><>(argstream& s,const ValuesHolder& v); + std::string name() const; + std::string description() const; + typedef T value_type; + private: + mutable O value_; + std::string description_; + int len_; + char letter_; + }; + template + inline ValuesHolder + values(const O& o, + const char* desc="", + int len=-1) + { + return ValuesHolder(o,desc,len); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueParser + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueParser + { + public: + inline T operator()(const std::string& s) const + { + std::istringstream is(s); + T t; + is>>t; + return t; + } + }; + // We need to specialize for string otherwise parsing of a value that + // contains space (for example a string with space passed in quotes on the + // command line) would parse only the first element of the value!!! + template <> + class ValueParser + { + public: + inline std::string operator()(const std::string& s) const + { + return s; + } + }; + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of argstream + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class argstream + { + public: + inline argstream(int argc,char** argv); + //inline argstream(const char* c); + template + friend argstream& operator>>(argstream& s,const ValueHolder& v); + friend inline argstream& operator>>(argstream& s,const OptionHolder& v); + template + friend argstream& operator>>(argstream& s,const ValuesHolder& v); + + inline bool helpRequested() const; + inline bool isOk() const; + inline std::string errorLog() const; + inline std::string usage() const; + inline void defaultErrorHandling(bool ignoreUnused=false) const; + static inline char uniqueLetter(); + protected: + void parse(int argc,char** argv); + private: + typedef std::list::iterator value_iterator; + typedef std::pair help_entry; + std::string progName_; + std::map options_; + std::list values_; + bool minusActive_; + bool isOk_; + std::deque argHelps_; + std::string cmdLine_; + std::deque errors_; + bool helpRequested_; + }; + //************************************************************ + // Implementation of ValueHolder + //************************************************************ + template + ValueHolder::ValueHolder(char s, + const char* l, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + ValueHolder::ValueHolder(const char* l, + T& v, + const char* desc, + bool mandatory) + : longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + ValueHolder::ValueHolder(char s, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + std::string + ValueHolder::name() const + { + std::ostringstream os; + if (!shortName_.empty()) os<<'-'< + std::string + ValueHolder::description() const + { + std::ostringstream os; + os< + //************************************************************ + template + ValuesHolder::ValuesHolder(const O& o, + const char* desc, + int len) + : value_(o), + description_(desc), + len_(len) + { + letter_ = argstream::uniqueLetter(); + } + template + std::string + ValuesHolder::name() const + { + std::ostringstream os; + os< + std::string + ValuesHolder::description() const + { + return description_; + } + //************************************************************ + // Implementation of argstream + //************************************************************ + inline + argstream::argstream(int argc,char** argv) + : progName_(argv[0]), + minusActive_(true), + isOk_(true) + { + parse(argc,argv); + } + //inline + // argstream::argstream(const char* c) + // : progName_(""), + // minusActive_(true), + // isOk_(true) + //{ + // std::string s(c); + // // Build argc, argv from s. We must add a dummy first element for + // // progName because parse() expects it!! + // std::deque args; + // args.push_back(""); + // std::istringstream is(s); + // while (is.good()) + // { + // std::string t; + // is>>t; + // args.push_back(t); + // } + // char* pargs[args.size()]; + // char** p = pargs; + // for (std::deque::const_iterator + // iter = args.begin(); + // iter != args.end();++iter) + // { + // *p++ = const_cast(iter->c_str()); + // } + // parse(args.size(),pargs); + //} + inline void + argstream::parse(int argc,char** argv) + { + // Run thru all arguments. + // * it has -- in front : it is a long name option, if remainder is empty, + // it is an error + // * it has - in front : it is a sequence of short name options, if + // remainder is empty, deactivates option (- will + // now be considered a char). + // * if any other char, or if option was deactivated + // : it is a value. Values are split in parameters + // (immediately follow an option) and pure values. + // Each time a value is parsed, if the previously parsed argument was an + // option, then the option is linked to the value in case of it is a + // option with parameter. The subtle point is that when several options + // are given with short names (ex: -abc equivalent to -a -b -c), the last + // parsed option is -c). + // Since we use map for option, any successive call overides the previous + // one: foo -a -b -a hello is equivalent to foo -b -a hello + // For values it is not true since we might have several times the same + // value. + value_iterator* lastOption = NULL; + for (char** a = argv,**astop=a+argc;++a!=astop;) + { + std::string s(*a); + if (minusActive_ && s[0] == '-') + { + if (s.size() > 1 && s[1] == '-') + { + if (s.size() == 2) + { + minusActive_ = false; + continue; + } + lastOption = &(options_[s.substr(2)] = values_.end()); + } + else + { + if (s.size() > 1) + { + // Parse all chars, if it is a minus we have an error + for (std::string::const_iterator cter = s.begin(); + ++cter != s.end();) + { + if (*cter == '-') + { + isOk_ = false; + std::ostringstream os; + os<<"- in the middle of a switch "<::const_iterator + iter = options_.begin();iter != options_.end();++iter) + { + std::cout<<"DEBUG: option "<first; + if (iter->second != values_.end()) + { + std::cout<<" -> "<<*(iter->second); + } + std::cout<::const_iterator + iter = values_.begin();iter != values_.end();++iter) + { + std::cout<<"DEBUG: value "<<*iter<::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + if (lmaxfirst.size()) lmax = iter->first.size(); + } + for (std::deque::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + os<<'\t'<first<first.size(),' ') + <<" : "<second<<'\n'; + } + return os.str(); + } + inline std::string + argstream::errorLog() const + { + std::string s; + for(std::deque::const_iterator iter = errors_.begin(); + iter != errors_.end();++iter) + { + s += *iter; + s += '\n'; + } + return s; + } + inline char + argstream::uniqueLetter() + { + static unsigned int c = 'a'; + return c++; + } + template + argstream& + operator>>(argstream& s,const ValueHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: searching "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line, either it + // has an associated value in which case we assign it, or it has not, in + // which case we have an error. + if (iter->second != s.values_.end()) + { +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: found value "<<*(iter->second)< p; + *(v.value_) = p(*(iter->second)); + // The option and its associated value are removed, the subtle thing + // is that someother options might have this associated value too, + // which we must invalidate. + s.values_.erase(iter->second); + + // FIXME this loop seems to crash if a std::string is used as the value + //for (std::map::iterator + // jter = s.options_.begin();jter != s.options_.end();++jter) + //{ + // if (jter->second == iter->second) + // { + // jter->second = s.values_.end(); + // } + //} + s.options_.erase(iter); + } + else + { + s.isOk_ = false; + std::ostringstream os; + os<<"No value following switch "<first + <<" on command line"; + s.errors_.push_back(os.str()); + } + } + else + { + if (v.mandatory_) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Mandatory parameter "; + if (!v.shortName_.empty()) os<<'-'<>(argstream& s,const OptionHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: searching "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line then the + // option is true and if an associated value was found, it is ignored + if (v.value_ != NULL) + { + *(v.value_) = true; + } + else + { + s.helpRequested_ = true; + } + // The option only is removed + s.options_.erase(iter); + } + else + { + if (v.value_ != NULL) + { + *(v.value_) = false; + } + else + { + s.helpRequested_ = false; + } + } + return s; + } + template + argstream& + operator>>(argstream& s,const ValuesHolder& v) + { + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + { + std::ostringstream os; + os<<' '<::iterator first = s.values_.begin(); + // We add to the iterator as much values as we can, limited to the length + // specified (if different of -1) + int n = v.len_ != -1?v.len_:s.values_.size(); + while (first != s.values_.end() && n-->0) + { + // Read the value from the string *first + ValueParser p; + *(v.value_++) = p(*first ); + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + // The value we just removed was maybe "remembered" by an option so we + // remove it now. + for (std::map::iterator + jter = s.options_.begin();jter != s.options_.end();++jter) + { + if (jter->second == first) + { + jter->second = s.values_.end(); + } + } + ++first; + } + // Check if we have enough values + if (n != 0) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Expecting "<