Skip to content
Snippets Groups Projects
util.h 12.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • toole1's avatar
    toole1 committed
    /* CS 225 Util Library
     * 
     * @author Jack Toole
     */
    
    
    toole1's avatar
    toole1 committed
    #ifndef UTIL_H
    #define UTIL_H
    
    
    toole1's avatar
    toole1 committed
    #define __STDC_LIMIT_MACROS
    
    #include <errno.h>
    
    toole1's avatar
    toole1 committed
    #include <limits.h>
    
    toole1's avatar
    toole1 committed
    #include <stdio.h>
    
    toole1's avatar
    toole1 committed
    #include <stdint.h>
    
    toole1's avatar
    toole1 committed
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    
    toole1's avatar
    toole1 committed
    #include <time.h>
    
    toole1's avatar
    toole1 committed
    #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
    	}
    };
    
    
    
    /**
    *  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;
    
    
    toole1's avatar
    toole1 committed
    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 ** argv);
    };
    
    toole1's avatar
    toole1 committed
    
    // 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); }
    
    
    toole1's avatar
    toole1 committed
    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()); }
    
    toole1's avatar
    toole1 committed
    
    // 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();
    
    
    toole1's avatar
    toole1 committed
    int  chdir(const string & dir);
    
    toole1's avatar
    toole1 committed
    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);
    
    toole1's avatar
    toole1 committed
    vector<string> get_files_in_dir(const string & dir, bool concatdir = true);
    
    toole1's avatar
    toole1 committed
    bool is_symlink(const string & file);
    string get_symlink_target(const string & symlink);
    
    toole1's avatar
    toole1 committed
    
    // 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);
    
    
    // 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
    int intlen(unsigned int a);
    void makeLower(string & str);
    string toLower(const string & str);
    
    
    toole1's avatar
    toole1 committed
    // String concatenation
    template <typename T>
    string to_string(const T & value);
    
    toole1's avatar
    toole1 committed
    template <typename T>
    T from_string(const string & s);
    template <typename T, typename F>
    T lexical_cast(const F & from);
    
    toole1's avatar
    toole1 committed
    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);
    
    
    toole1's avatar
    toole1 committed
    // CLOCK / TIMING
    uint64_t process_clock();
    
    
    toole1's avatar
    toole1 committed
    // 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__)
    
    
    toole1's avatar
    toole1 committed
    // 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
    
    
    toole1's avatar
    toole1 committed
    
    // 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();
    }
    
    
    toole1's avatar
    toole1 committed
    // 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)
    {
    	T to;
    	stringstream ss;
    	if (!(ss << from))
    	{
    		cerr << "ERROR: Could not convert types" << endl;
    		return to;
    	}
    	if (!(ss >> to))
    	{
    		cerr << "ERROR: Could not convert types" << endl;
    		return to;
    	}
    	return to;
    }
    
    
    toole1's avatar
    toole1 committed
    inline int intlen(unsigned int a)
    {
    	int 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;
    }
    
    
    toole1's avatar
    toole1 committed
    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); }
    
    toole1's avatar
    toole1 committed
    template <typename T>
    inline std::string & operator+=(std::string & str, const T & value)
    {
    	str += util::to_string(value);
    	return str;
    
    toole1's avatar
    toole1 committed
    template <typename T>
    inline std::string operator+(const std::string & str, const T & value)
    {
    	std::stringstream ss;
    	ss << str << value;
    	return ss.str();
    }
    
    toole1's avatar
    toole1 committed
    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
    }
    
    
    toole1's avatar
    toole1 committed
    } // namespace util
    
    
    toole1's avatar
    toole1 committed
    #endif // UTIL_H