/* CS 225 Util Library * * @author Jack Toole */ #ifndef UTIL_H #define UTIL_H #define __STDC_LIMIT_MACROS #include <errno.h> #include <limits.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> #include <time.h> #include <unistd.h> #include <fstream> #include <iostream> #include <map> #include <sstream> #include <string> #include <vector> namespace util { using namespace std; namespace internal { extern const char * error_prefix; } /************************************************************************/ /* Comparator for case-insensitive comparison in STL assos. containers */ /* From Abhay: */ /* http://stackoverflow.com/questions/1801892/making-mapfind-operation-case-insensitive */ /************************************************************************/ struct ci_less : std::binary_function<std::string, std::string, bool> { // case-independent (ci) compare_less binary function struct nocase_compare : public std::binary_function<unsigned char,unsigned char,bool> { bool operator() (const unsigned char& c1, const unsigned char& c2) const { return tolower (c1) < tolower (c2); } }; bool operator() (const std::string & s1, const std::string & s2) const { return std::lexicographical_compare (s1.begin (), s1.end (), // source range s2.begin (), s2.end (), // dest range nocase_compare ()); // comparison } }; // http://stackoverflow.com/questions/5300602/template-return-type-with-default-value template <typename T> struct Initializer { T value; Initializer() :value() // ====> default construction, works for classes _and_ built-in { } }; class Signal { private: const int signum; public: Signal(int signal_number) : signum(signal_number) { } int number() const { return signum; } const char * what() const; }; /** * Here we create a useful and easily understanable alias for the map. **/ typedef map<string, vector<string>, ci_less> FileMap; typedef map<string, bool, ci_less> OptionsMap; class OptionsParser { private: typedef map<string, bool*> optsMap_t; typedef map<string, bool> valueMap_t; valueMap_t valueMap; // not static to prevent still reachable memory optsMap_t optsMap; vector<string *> args; public: OptionsParser(); void addOption(const string & name, bool & setValue) { optsMap[name] = &setValue; } void addArg(string & setValue) { args.push_back(&setValue); } vector<string> parse(int argc, const char * const * argv); }; // EXEC() int8_t exec(int redirect_fd, const char * command, const char * arg1 = NULL, const char * arg2 = NULL, const char * arg3 = NULL, const char * arg4 = NULL, const char * arg5 = NULL, const char * arg6 = NULL); inline int8_t exec(const char * command, const char * arg1 = NULL, const char * arg2 = NULL, const char * arg3 = NULL, const char * arg4 = NULL, const char * arg5 = NULL, const char * arg6 = NULL) { return exec(STDOUT_FILENO, command, arg1, arg2, arg3, arg4, arg5, arg6); } inline int8_t exec(const string & command) { return exec(command.c_str()); } inline int8_t exec(const string & command, const string & arg1) { return exec(command.c_str(), arg1.c_str()); } inline int8_t exec(const string & command, const string & arg1, const string & arg2) { return exec(command.c_str(), arg1.c_str(), arg2.c_str()); } inline int8_t exec(const string & command, const string & arg1, const string & arg2, const string & arg3) { return exec(command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str()); } inline int8_t exec(const string & command, const string & arg1, const string & arg2, const string & arg3, const string & arg4) { return exec(command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str(), arg4.c_str()); } inline int8_t exec(const string & command, const string & arg1, const string & arg2, const string & arg3, const string & arg4, const string & arg5) { return exec(command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str(), arg4.c_str(), arg5.c_str()); } inline int8_t exec(const string & command, const string & arg1, const string & arg2, const string & arg3, const string & arg4, const string & arg5, const string & arg6) { return exec(command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str(), arg4.c_str(), arg5.c_str(), arg6.c_str()); } inline int8_t exec(int redirect_fd, const string & command) { return exec(redirect_fd, command.c_str()); } inline int8_t exec(int redirect_fd, const string & command, const string & arg1) { return exec(redirect_fd, command.c_str(), arg1.c_str()); } inline int8_t exec(int redirect_fd, const string & command, const string & arg1, const string & arg2) { return exec(redirect_fd, command.c_str(), arg1.c_str(), arg2.c_str()); } inline int8_t exec(int redirect_fd, const string & command, const string & arg1, const string & arg2, const string & arg3) { return exec(redirect_fd, command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str()); } inline int8_t exec(int redirect_fd, const string & command, const string & arg1, const string & arg2, const string & arg3, const string & arg4) { return exec(redirect_fd, command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str(), arg4.c_str()); } inline int8_t exec(int redirect_fd, const string & command, const string & arg1, const string & arg2, const string & arg3, const string & arg4, const string & arg5) { return exec(redirect_fd, command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str(), arg4.c_str(), arg5.c_str()); } inline int8_t exec(int redirect_fd, const string & command, const string & arg1, const string & arg2, const string & arg3, const string & arg4, const string & arg5, const string & arg6) { return exec(redirect_fd, command.c_str(), arg1.c_str(), arg2.c_str(), arg3.c_str(), arg4.c_str(), arg5.c_str(), arg6.c_str()); } int8_t exec(int redirect_fd, const string & command, const vector<string> & args); int8_t exec(const string & command, const vector<string> & args, ostream * output); inline int8_t exec(const string & command, const vector<string> & args) { return exec(command, args, &std::cout); } // FILESYSTEM FUNCTIONS void assertExists(const string & path, int exit_code = -1); bool exists(const string & path); mode_t permissions(const string & path); void forceRemoveDir(string dir); string getcwdstr(); int chdir(const string & dir); void copyFile(const string & source, const string & dest); void copyFiles(const string & sourceFolder, const string & destFolder, const vector<string> & files); void protectFiles(const string & folder, const vector<string> & files); void protectDir(const string & dir); void linkDirs(const string & sourceFolder, const string & destFolder, const vector<string> & dirs); vector<string> get_files_in_dir(const string & dir, bool concatdir = true); bool is_symlink(const string & file); string get_symlink_target(const string & symlink); // STRING REPLACEMENT bool replaceFirst(string & str, const string & toreplace, const string & with); size_t replaceAll (string & str, const string & toreplace, const string & with); size_t replaceAllInternal(string & str, const string & toreplace, const string & with); size_t findNthLast(const string & str, char c, size_t n); vector<string> tokenize(const string & str, char delim); vector<string> tokenize(const string & str, const string & delims); // IO OPERATIONS string read_string_from_FILE(FILE * file, size_t max_length = -1); void write_string_to_FILE(FILE * file, const char * str); ssize_t writeBytesToFile(signed int fileDescriptor, const char * buffer, unsigned int bufferLength); ssize_t writen(int fd, const void *vptr, size_t n); ssize_t write(int fd, const string & str); ssize_t write(int fd, int val); ssize_t write(int fd, long val); ssize_t readn(int fd, void *vptr, size_t n); ssize_t read(int fd, int & val); ssize_t read(int fd, long & val); // STRING TYPE OPERATIONS uint32_t intlen(uint32_t a); void makeLower(string & str); string toLower(const string & str); // String concatenation template <typename T> string to_string(const T & value); template <typename T> T from_string(const string & s); template <typename T, typename F> T lexical_cast(const F & from); string operator+(const string & lhs, const string & rhs); // These 5 functions are to disambiguate string operator+(const string & lhs, const char * rhs); // operator+ so that the following string operator+(const string & lhs, char rhs); // templates may exist string operator+(const char * lhs, const string & rhs); string operator+(char lhs, const string & rhs); template <typename T> string & operator+=(string & str, const T & value); template <typename T> string operator+(const string & str, const T & value); // CLOCK / TIMING uint64_t process_clock(); uint64_t system_clock(); // CONFIGURATION void readConfig(const string & testsFolder, FileMap & map, const string & discriminator = ""); void readFile(const string & file, vector<string> & lines); string readFile(const string & filename); void readFileGeneric(const string & file, FileMap * map, vector<string> * lines, const string & discriminator = ""); char * processOptions(int argc, char ** argv, OptionsMap & opts, vector<string> & args); // AUTOGRADER // STUDENT CODE COMPILATION FUNCTIONS void rename_main(const string & file, const string & newname); // MACROS void SET_ERROR_MESSAGE(const char * message); #define STRINGIFY1(p) #p #define STR(p) STRINGIFY1(p) namespace internal { template<typename StrType> void exit_if_error_output(const char * file, int32_t line, StrType message); } #define EXIT_IF_ERROR2(statement_check, message) \ do { \ errno = 0; \ if ((statement_check) || errno != 0) \ util::internal::exit_if_error_output(__FILE__, __LINE__, message); \ } while (0) #define EXIT_IF_ERROR1(statement_check) \ EXIT_IF_ERROR2(statement_check, #statement_check) // Crazy hack for overloading! // Arg counting from: // http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/ // Overloading tips: // http://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros #define EXIT_IF_ERROR_THIRD_ARG(a, b, c, ...) c #define EXIT_IF_ERROR(...) \ EXIT_IF_ERROR_THIRD_ARG(__VA_ARGS__, \ EXIT_IF_ERROR2, \ EXIT_IF_ERROR1, 0) (__VA_ARGS__) // Colorization namespace colorize { extern const char * BLACK; extern const char * GREEN; extern const char * RED; extern const bool is_color_enabled; inline string make_color(const char * color, const string & str) { return (is_color_enabled ? color + str + BLACK : str); } } // namespace colorize // INLINE IMPLEMENTATIONS // Originally by radu // http://notfaq.wordpress.com/2006/08/30/c-convert-int-to-string/ template <typename T> inline string to_string(const T & value) { stringstream ss; ss << value; return ss.str(); } // http://stackoverflow.com/questions/5017001/like-atoi-but-to-float template <typename T> inline T from_string(const string & s) { stringstream ss(s); T value; ss >> value; return value; } template <typename T, typename F> inline T lexical_cast(const F & from) { Initializer<T> to; stringstream ss; if (!(ss << from)) { cerr << "ERROR: Could not convert types" << endl; return to.value; } if (!(ss >> to.value)) { cerr << "ERROR: Could not convert types" << endl; return to.value; } return to.value; // TODO (toole1): Not sure if this forces a copy } inline uint32_t intlen(uint32_t a) { uint32_t len = 1; a /= 10; while (a != 0) { a = a/10; len++; } return len; } inline ssize_t write(int fd, const string & str) { return writen(fd, str.c_str(), str.length()+1); } inline ssize_t write(int fd, int val) { return writen(fd, &val, sizeof val); } inline ssize_t write(int fd, long val) { return writen(fd, &val, sizeof val); } inline ssize_t read(int fd, int & val) { return readn(fd, &val, sizeof val); } inline ssize_t read(int fd, long & val) { return readn(fd, &val, sizeof val); } template <typename T, typename C, typename BinaryOp> T accumulate(const C & collect, BinaryOp op, T init) { typename C::const_iterator it = collect.begin(); typename C::const_iterator end = collect.end(); while (it != end) init = init + *it++; return init; } inline string operator+(const string & lhs, const string & rhs) { return std::operator+(lhs, rhs); } inline string operator+(const string & lhs, const char * rhs) { return std::operator+(lhs, rhs); } inline string operator+(const string & lhs, char rhs) { return std::operator+(lhs, rhs); } inline string operator+(char lhs, const string & rhs) { return std::operator+(lhs, rhs); } inline string operator+(const char * lhs, const string & rhs) { return std::operator+(lhs, rhs); } template <typename T> inline std::string & operator+=(std::string & str, const T & value) { str += util::to_string(value); return str; } template <typename T> inline std::string operator+(const std::string & str, const T & value) { std::stringstream ss; ss << str << value; return ss.str(); } inline uint64_t process_clock() { #ifdef CLOCK_PROCESS_CPUTIME_ID timespec ts; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); return ts.tv_sec * 1000000 + (ts.tv_nsec + 500) / 1000; #else return clock(); #endif } inline uint64_t system_clock() { timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000000 + tv.tv_usec; } } // namespace util #endif // UTIL_H