Skip to content
Snippets Groups Projects
util.cpp 19.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • toole1's avatar
    toole1 committed
    // CS 225 util.h
    // Created Spring 2011 by Jack Toole
    
    #include <ctype.h>
    #include <dirent.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <iostream>
    #include "util.h"
    
    extern char ** environ; // man 7 environ
    
    namespace util
    {
    
    namespace internal
    {
    const char * error_prefix = "";
    
    template<typename StrType>
    void exit_if_error_output(const char * file, int32_t line, StrType message)
    {
    	if (util::internal::error_prefix != NULL)
    		cerr << util::internal::error_prefix;
    	cerr << file << ":" << line << ": " << message;
    	if (errno != 0)
    		cerr << ": " << strerror(errno);
    	cerr << endl;
    	exit(-1);
    }
    
    }
    
    void SET_ERROR_MESSAGE(const char * message)
    {
    	internal::error_prefix = message;
    }
    
    // originally from stackoverflow.com user plinth
    // http://stackoverflow.com/questions/2180079/how-can-i-copy-a-file-on-unix-using-c
    // Modified by Jack Toole
    int8_t exec(int redirect_fd, const char * command,
                const char * arg1,
                const char * arg2,
                const char * arg3,
                const char * arg4,
                const char * arg5,
                const char * arg6)
    {
    	int childExitStatus;
    	pid_t pid;
    
    	// For debugging:
    #if 0
    	cerr << "exec(" << command << ' '
    	     << ((arg1!=NULL)?arg1:"-") << ' '
    	     << ((arg2!=NULL)?arg2:"-") << ' '
    	     << ((arg3!=NULL)?arg3:"-") << ' '
    	     << ((arg4!=NULL)?arg4:"-") << ' '
    	     << ((arg5!=NULL)?arg5:"-") << ' '
    	     << ((arg6!=NULL)?arg6:"-") << ' '
    	     << ')' << endl;
    #endif
    
    	// avoid self destruction errors from closing then trying to duplicate output
    	// you can't redirect to what's already there
    	if (redirect_fd == STDOUT_FILENO || redirect_fd == STDERR_FILENO)
    		redirect_fd = STDOUT_FILENO;
    
    	// Save timer values :)
    	// These are preserved across the parent, but not inherited by the child
    	// let's change that
    	struct itimerval remaining_real;
    	struct itimerval remaining_virtual;
    	struct itimerval remaining_prof;
    
    toole1's avatar
    toole1 committed
    	bool supports_virtual = true;
    	bool supports_prof    = true;
    
    toole1's avatar
    toole1 committed
    	EXIT_IF_ERROR(getitimer(ITIMER_REAL,    &remaining_real));
    
    toole1's avatar
    toole1 committed
    	if (getitimer(ITIMER_VIRTUAL, &remaining_virtual) != 0)
    	{
    		if (errno == EINVAL)
    		{
    			supports_virtual = false;
    			errno = 0;
    		}
    		else
    			internal::exit_if_error_output(__FILE__, __LINE__, "getitimer(ITIMER_VIRTUAL) failed");
    	}
    	if (getitimer(ITIMER_PROF, &remaining_prof) != 0)
    	{
    		if (errno == EINVAL)
    		{
    			supports_prof = false;
    			errno = 0;
    		}
    		else
    			internal::exit_if_error_output(__FILE__, __LINE__, "getitimer(ITIMER_PROF) failed");
    	}
    
    toole1's avatar
    toole1 committed
    
    	pid = fork();
    
    	if (pid == 0) /* child */
    	{
    
    		// Restore timers
    
    toole1's avatar
    toole1 committed
    		EXIT_IF_ERROR(setitimer(ITIMER_REAL, &remaining_real, NULL));
    		if (supports_virtual) EXIT_IF_ERROR(setitimer(ITIMER_VIRTUAL, &remaining_virtual, NULL));
    		if (supports_prof)    EXIT_IF_ERROR(setitimer(ITIMER_PROF,    &remaining_prof, NULL));
    
    toole1's avatar
    toole1 committed
    
    		if (redirect_fd == -1)
    		{
    			int devnull_fd = open("/dev/null", O_WRONLY | O_NONBLOCK);
    			close(STDOUT_FILENO);
    			close(STDERR_FILENO);
    			dup2(devnull_fd, STDOUT_FILENO);
    			dup2(devnull_fd, STDERR_FILENO);
    			close(devnull_fd);
    		}
    		else if (redirect_fd != STDOUT_FILENO)
    		{
    			close(STDOUT_FILENO);
    			close(STDERR_FILENO);
    			dup2(redirect_fd, STDOUT_FILENO);
    			dup2(redirect_fd, STDERR_FILENO);
    		}
    
    		// Sanitize the environment
    
    toole1's avatar
    toole1 committed
    #if 1 //!! hack!
    
    toole1's avatar
    toole1 committed
    		char path[] = "PATH=/bin/:/usr/bin:/usr/local/bin";
    
    toole1's avatar
    toole1 committed
    		char redirect_glibc[] = "LIBC_FATAL_STDERR_=1";
    		char * newenv[] = { path, redirect_glibc, NULL };
    		//char * newenv[] = { path, NULL };
    
    toole1's avatar
    toole1 committed
    		environ = newenv;
    
    toole1's avatar
    toole1 committed
    #endif
    
    toole1's avatar
    toole1 committed
    
    		// Swap out child process image with the command, searching
    		// in the specified path
    		execlp(command, command, arg1, arg2, arg3, arg4, arg5, arg6, NULL);
    		
            // An error occured
    
    massung1's avatar
    massung1 committed
    		cerr << "exec(" << '\"' << command << '\"';
    
    toole1's avatar
    toole1 committed
    		if (arg1 != NULL) cerr << ", \"" << arg1 << "\"";
    		if (arg2 != NULL) cerr << ", \"" << arg2 << "\"";
    		if (arg3 != NULL) cerr << ", \"" << arg3 << "\"";
    		if (arg4 != NULL) cerr << ", \"" << arg4 << "\"";
    		if (arg5 != NULL) cerr << ", \"" << arg5 << "\"";
    		if (arg6 != NULL) cerr << ", \"" << arg6 << "\"";
    		cerr << ") failed: " << strerror(errno) << endl;
    		exit(-1);
    	}
    	else if (pid < 0)
    	{
    		/* error - couldn't start process - you decide how to handle */
    		return -1;
    	}
    	else
    	{
    		/* parent - wait for child - this has all error handling, you
    		 * could just call wait() as long as you are only expecting to
    		 * have one child process at a time.
    		 */
    		pid_t ws = waitpid( pid, &childExitStatus, 0);
    		if (ws == -1)
    		{ /* error - handle as you wish */
    			//cout << "exec error: " << __LINE__ << endl;
    			return -1;
    		}
    
    		if (WIFEXITED(childExitStatus)) /* exit code in childExitStatus */
    		{
    			int8_t status = WEXITSTATUS(childExitStatus); /* zero is normal exit */
    			/* handle non-zero as you wish */
    			return status;
    		}
    		else if (WIFSIGNALED(childExitStatus)) /* killed */
    		{
    			kill(getpid(), WTERMSIG(childExitStatus));
    			return -1;
    		}
    		else if (WIFSTOPPED(childExitStatus)) /* stopped */
    		{
    			//cout << "exec error: " << __LINE__ << endl;
    			return -1;
    		}
    		else
    			return -1;
    	}
    }
    
    
    
    toole1's avatar
    toole1 committed
    int chdir(const string & dir)
    {
    	return ::chdir(dir.c_str());
    }
    
    
    toole1's avatar
    toole1 committed
    void assertExists(const string & path, int exit_code /* = -1 */)
    {
    	if (!exists(path))
    	{
    		cerr << "Error: " << path << " does not exist." << endl;
    		exit(exit_code);
    	}
    }
    
    bool exists(const string & path)
    {
    	// Try stat-ing it
    	struct stat st;
    	if (stat(path.c_str(), &st) != 0) return false;
    	// Check for read permission
    	if ((st.st_mode & S_IRUSR) == 0) return false;
    
    	// Check for correct file/directory nature
    	if (path[path.length()-1] != '/') return S_ISREG(st.st_mode);
    
    	// Otherwise we want a directory
    	if ((st.st_mode & S_IXUSR) == 0) return false;
    	return S_ISDIR(st.st_mode);
    }
    
    
    mode_t permissions(const string & path)
    {
    	// Try stat-ing it
    	struct stat st;
    	if (stat(path.c_str(), &st) != 0) return -1;
    	// Check for read permission
    	if ((st.st_mode & S_IRUSR) == 0) return -1;
    
    	return (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
    }
    
    
    void forceRemoveDir(string dir)
    {
    	size_t len = dir.length();
    	if (dir[len-1] == '/') dir[len-1] = '\0';
    	EXIT_IF_ERROR(exec("rm","-rf",dir.c_str()) != 0);
    	if (dir[len-1] == '\0') dir[len-1] = '/';
    }
    
    
    string getcwdstr()
    {
    	int len = 256;
    	char * buffer = new char[len];
    
    	char * ret = getcwd(&buffer[0], len - 1);
    	while (ret == NULL && errno == ERANGE)
    	{
    		len *= 2;
    
    		delete buffer;
    		buffer = new char[len];
    
    		ret = getcwd(&buffer[0], len - 1);
    	}
    
    	EXIT_IF_ERROR(ret == NULL);
    
    	string cwdstr(buffer);
    	delete buffer;
    
    	return cwdstr;
    }
    
    
    void copyFile(const string & source, const string & dest)
    {
    	assertExists(source);
    	vector<string> folders = tokenize(dest, '/');
    	string currdir = "";
    	for (size_t i = 0; i < folders.size() - 1; i++)
    	{
    		currdir += folders[i] + '/';
    		if (!exists(currdir))
    			exec("mkdir", currdir.c_str());
    	}
    	exec("cp", source.c_str(), dest.c_str());
    }
    
    void copyFiles(const string & sourceFolder, const string & destFolder, const vector<string> & files)
    {
    	assertExists(destFolder);
    	for (size_t i = 0; i < files.size(); i++)
    	{
    		string sourceFile = sourceFolder + files[i];
    		assertExists(sourceFile);
    		copyFile(sourceFile, destFolder);
    	}
    }
    
    
    void protectFiles(const string & folder, const vector<string> & files)
    {
    #if 0 // (debug)
    	for (size_t i = 0; i < files.size(); i++)
    	{
    		string file = folder + files[i];
    		assertExists(file);
    
    		if (chmod(file.c_str(), S_IRUSR) != 0)
    		{
    			perror("chmod failed");
    			exit(-1);
    		}
    	}
    #endif
    }
    
    void protectDir(const string & dir)
    {
    	// (debug) EXIT_IF_ERROR(exec("/bin/chmod", "-R", "ugoa-w", dir.c_str()) != 0);
    }
    
    // Originally from Simon Biber
    // http://bytes.com/topic/c/answers/545614-list-files-current-directory
    
    toole1's avatar
    toole1 committed
    vector<string> get_files_in_dir(const string & dir, bool concatdir /* = true */)
    
    toole1's avatar
    toole1 committed
    	EXIT_IF_ERROR(dir == "" || dir[dir.length()-1] != '/', "Directory name must end in a '/'");
    	
    
    toole1's avatar
    toole1 committed
    	vector<string> files;
    	DIR * dirp = opendir(dir.c_str());
    	if (dirp == NULL) return files;
    	
    	struct dirent * ent = readdir(dirp);
    	while (ent != NULL)
    	{
    
    toole1's avatar
    toole1 committed
    		string file = ent->d_name;
    		if (file != "." && file != "..")
    
    toole1's avatar
    toole1 committed
    			files.push_back(concatdir ? dir + file : file);
    
    toole1's avatar
    toole1 committed
    		ent = readdir(dirp);
    	}
    
    	closedir(dirp);
    	return files;
    }
    
    
    toole1's avatar
    toole1 committed
    bool is_symlink(const string & file)
    {
    	// Try lstat-ing it
    	struct stat st;
    	if (lstat(file.c_str(), &st) != 0) return -1;
    	// Check for read permission
    	if ((st.st_mode & S_IRUSR) == 0) return false;
    
    	// & with symlink bit
    	return (S_ISLNK(st.st_mode)) != 0;
    }
    
    string get_symlink_target(const string & symlink)
    {
    	const size_t buf_size = 4096;
    	char buf[buf_size+1]; // TODO (toole1): hack-y value
    	ssize_t len = readlink(symlink.c_str(), buf, buf_size);
    	EXIT_IF_ERROR(len < 0 || static_cast<size_t>(len) == buf_size, "Error getting target of symlink " + symlink);
    	buf[len] = '\0';
    	return string(buf);
    }
    
    
    toole1's avatar
    toole1 committed
    void linkDirs(const string & sourceFolder, const string & destFolder, const vector<string> & dirs)
    {
    	assertExists(destFolder);
    	for (size_t i = 0; i < dirs.size(); i++)
    	{
    		string source = sourceFolder + dirs[i];
    		string target = destFolder   + dirs[i];
    
    		// Check for redundant monad/ directory
    		// This allows the monad/ dir to be safely renamed
    		if (replaceFirst(source, "/../monad/","/"))
    			replaceFirst(target, "/monad/","/");
    
    		assertExists(destFolder + source + '/');
    
    		if (symlink(source.c_str(), target.c_str()) != 0)
    		{
    			cerr << "symlink failed: " << target << ": ";
    			perror(NULL);
    			exit(-1);
    		}
    	}
    }
    
    
    bool replaceFirst(string & str, const string & toreplace, const string & with)
    {
    	size_t i = str.find(toreplace);
    	if (i != string::npos)
    	{
    		str.replace(i,toreplace.length(),with);
    		return true;
    	}
    	return false;
    }
    
    size_t replaceAll(string & str, const string & toreplace, const string & with)
    {
    	size_t i = str.find(toreplace);
    	size_t count = 0;
    
    	while (i != string::npos)
    	{
    		str.replace(i,toreplace.length(),with);
    		i = str.find(toreplace, i + with.length());
    		count++;
    	}
    
    	return count;
    }
    
    size_t replaceAllInternal(string & str, const string & toreplace, const string & with)
    {
    	size_t i = str.find(toreplace);
    	size_t count = 0;
    
    	while ((i != string::npos) && (i != str.length() - toreplace.length()))
    	{
    		str.replace(i,toreplace.length(),with);
    		i = str.find(toreplace, i + with.length());
    		count++;
    	}
    
    	return count;
    }
    
    
    size_t findNthLast(const string & str, char c, size_t n)
    {
    	if (str.length() == 0) return string::npos;
    	size_t i = str.length() - 1;
    
    	do
    	{
    		if (str[i] == c) n--;
    		if (n == 0) return i;
    	} while (i-- != 0);
    
    	return string::npos;
    }
    
    
    string read_string_from_FILE(FILE * file, size_t max_length /* = -1 */)
    {
    	vector<char> v;
    	v.reserve(256);
    
    	while (true) 
    	{
    		int nextchar = fgetc(file);
    		if (nextchar == '\0' || nextchar == EOF)
    			break;
    		if (v.size() < max_length)
    			v.push_back(nextchar);
    	}
    
    	if (v.size() == max_length)
    	{
    		v.push_back('.');
    		v.push_back('.');
    		v.push_back('.');
    	}
    
    	v.push_back('\0');
    
    	return string(&v[0]);
    }
    
    void write_string_to_FILE(FILE * file, const char * str)
    {
    	fflush(file);
    	size_t i = 0;
    	do
    	{
    //		cout << (int)str[i] << ' ';
    		fputc(str[i], file);
    
    		// We use a do-while because we want the \0 to be written to the stream
    		// for sending multiple strings
    	} while (str[i++] != 0);
    
    //	cout << endl;
    
    	fflush(file);
    }
    
    
    
    /**
    *
    *
    **/
    
    string readFile(const string & filename)
    {
    	ifstream file;
    	file.open(filename.c_str());
    	if (!file.good())
    		return "";
    	
    	stringbuf linebuf;
    	file.get(linebuf, '\0');
    	linebuf.pubsync();
    	return linebuf.str();
    }
    
    
    void readConfig(const string & testsFolder, FileMap & map, const string & discriminator /* = "" */)
    {
    	string file;
    	if (testsFolder == "" || testsFolder[testsFolder.length()-1] == '/')
    		file = testsFolder + "config.ini";
    	else
    		file = testsFolder;
    	readFileGeneric(file, &map, NULL, discriminator);
    }
    
    void readFile(const string & file, vector<string> & lines)
    {
    	readFileGeneric(file, NULL, &lines);
    }
    
    void readFileGeneric(const string & filename, FileMap * map, vector<string> * lines, const string & discriminator /* = "" */)
    {
    	ifstream infile;
    	istream * fileptr;
    	if (filename == "/dev/stdin")
    		fileptr = &cin;
    	else
    	{
    		fileptr = &infile;
    		infile.open(filename.c_str(), fstream::in);
    	}
    	istream & file = *fileptr;
    
    	vector<string> * section = NULL;
    	if (map != NULL) section = &(*map)[""];
    	else section = lines;
    
    	while ((file.good() && file.peek() == '\n') || file.peek() == '\r')
    		file.get(); // get '\n'
    
    	while (file.good())
    	{
    		// Read a line - A lot of code, I know, right?
    		stringbuf linebuf;
    		file.get(linebuf);
    		while ((file.good() && file.peek() == '\n') || file.peek() == '\r')
    			file.get(); // get '\n'
    		if (linebuf.in_avail() == 0) continue;
    		linebuf.pubsync();
    		string line = linebuf.str();
    		int len = line.length();
                    if (line[len-1] == '\r')
                        line.replace(--len,1,"");
    
    		if (len == 0 || line[0] == ';') continue; // skip comments
    		
    		if (map != NULL)
    		{
    			// Update the section
    			if (line[0] == '[' && line[len-1] == ']')
    			{
    				section = &(*map)[line.substr(1, len - 2)];
    				continue;
    			}
    			else if (line[0] == '[' || line[len-1] == ']')
    			{
    				cout << "config.ini: Format error: " << line << endl;
    				exit(-1);
    			}
    		}
    
    		// Or add the line/file to the section
    		size_t delim_pos = line.find_first_of("?:");
    		if (delim_pos == string::npos || map == NULL)
    			section->push_back(line);
    		else if ((line[delim_pos] == ':' && (delim_pos == 0 || discriminator == "")) ||
    		         line.compare(0, delim_pos, discriminator) == 0)
    			section->push_back(line.substr(delim_pos+1, line.size()-delim_pos-1));
    	}
    
    	if (filename != "/dev/stdin")
    		infile.close();
    }
    
    
    
    toole1's avatar
    toole1 committed
    OptionsParser::OptionsParser()
    {
    	valueMap[""]      = true;
    
    	valueMap["yes"]   = true;
    	valueMap["no"]    = false;
    
    	valueMap["on"]    = true;
    	valueMap["off"]   = false;
    
    	valueMap["true"]  = true;
    	valueMap["false"] = false;
    
    	valueMap["1"]     = true;
    	valueMap["0"]     = false;
    }
    
    vector<string> OptionsParser::parse(int argc, const char ** argv)
    {
    	vector<string> unprocessedArgs;
    	size_t out_arg_i = 0;
    
    	for (int arg_i = 1; arg_i < argc; arg_i++)
    	{
    		string currarg = toLower(argv[arg_i]);
    
    		if (currarg.compare(0, 2, "--") == 0) //long option
    		{
    			bool invert = (currarg.compare(2, 2, "no") == 0);
    			size_t name_i = (invert ? 4 : 2);
    			size_t equalspos = currarg.find_first_of("=-", name_i);
    			
    			string name = currarg.substr(name_i, equalspos - name_i);
    			string value = (equalspos >= currarg.length()) ? "" : currarg.substr(equalspos);
    
    			optsMap_t::iterator option = optsMap.find(name);
    			if (option == optsMap.end())
    			{
    				cerr << "Unknown option: " << currarg << endl;
    				exit(-1);
    			}
    
    			valueMap_t::iterator valueIt = valueMap.find(value);
    			if (valueIt == valueMap.end())
    			{
    				cerr << "Unknown value: " << currarg << endl;
    				exit(-1);
    			}
    
    			*option->second = valueIt->second ^ invert;
    		} // "--"
    
    		else if (currarg[0] == '-') //string of single char options
    		{
    			for (size_t c = 1; currarg[c] != '\0'; c++)
    			{
    				optsMap_t::iterator option = optsMap.find(string(1,currarg[c]));
    				if (option == optsMap.end())
    				{
    					cerr << "Unknown option: -" << currarg[c] << endl;
    					exit(-1);
    				}
    				*option->second = true;
    			}
    		}
    
    		else //positional argument
    		{
    			if (out_arg_i < args.size())
    				*args[out_arg_i] = currarg;
    			else
    				unprocessedArgs.push_back(currarg);
    			out_arg_i++;
    		}
    	}
    	
    	return unprocessedArgs;
    }
    
    
    toole1's avatar
    toole1 committed
    char * processOptions(int argc, char ** argv, OptionsMap & opts, vector<string> & args)
    {
    	for (int arg_i = 1; arg_i < argc; arg_i++)
    	{
    		char * currarg = argv[arg_i];
    
    		if (strncmp(currarg, "--", 2) == 0) //long option
    		{
    			bool value, invert;
    			size_t string_i;
    
    			if (strncasecmp(currarg+2, "no", 2) == 0)
    			{
    				invert = true;
    				string_i = 4;
    			}
    			else
    			{
    				invert = false;
    				string_i = 2;
    			}
    			
    			size_t equals_i = string_i;
    			while (currarg[equals_i] != '\0' && currarg[equals_i] != '=')
    				equals_i++;
    			if (currarg[equals_i] == '=')
    				currarg[equals_i++] = '\0';
    
    			OptionsMap::iterator option = opts.find(currarg+string_i);
    
    			if (option == opts.end())
    			{
    				cerr << "Unknown option: " << currarg << endl;
    				return currarg;
    			}
    
    			char valuechar = tolower(currarg[equals_i]);
    			if (valuechar == 'o') valuechar = tolower(currarg[equals_i+1]) + 1;
    			switch (valuechar)
    			{
    				case '\0'  : value = true;  break;
    				case 'f'+1 : value = false; break; //off: see 'o' above
    				case 'n'   : value = false; break;
    				case 'n'+1 : value = true;  break; //on: contrast 'n': see 'o' above
    				case 't'   : value = true;  break;
    				case 'y'   : value = true;  break;
    				default:
    					cerr << "Unknown option value: " << currarg << endl;
    					return currarg;
    			}
    
    			(*option).second = value ^ invert;
    		} // "--"
    
    		else if (currarg[0] == '-') //string of single char options
    		{
    			for (size_t c = 1; currarg[c] != '\0'; c++)
    			{
    				OptionsMap::iterator option = opts.find(string(1,currarg[c]));
    				if (option == opts.end())
    				{
    					cerr << "Unknown option: -" << currarg[c] << endl;
    					currarg[1] = currarg[c];
    					currarg[2] = '\0';
    					return currarg;
    				}
    				(*option).second = true;
    			}
    		}
    
    		else //positional argument
    			args.push_back(currarg);
    	}
    	
    	return NULL;
    }
    
    
    
    void makeLower(string & str)
    {
    	for (size_t i = 0; i < str.length(); i++)
    	{
    		str[i] = tolower(str[i]);
    	}
    }
    
    string toLower(const string & str)
    {
    	string s(str);
    	makeLower(s);
    	return s;
    }
    
    
    
    /**
    *  A wrapper function which writes a buffer to a file.
    **/
    ssize_t writeBytesToFile(signed int fileDescriptor, const char * buffer, unsigned int bufferLength) {
    	return writen(fileDescriptor, buffer, bufferLength);
    }
    
    
    // From Steven's Unix Net Programming
    // http://www.kohala.com/start/
    /* Write "n" bytes to a descriptor. */
    ssize_t writen(int fd, const void *vptr, size_t n)
    {
    	size_t         nleft;
    	ssize_t        nwritten;
    	const int8_t * ptr;
    
    	ptr = static_cast<const int8_t*>(vptr);
    	nleft = n;
    	while (nleft > 0) {
    		if ( (nwritten = ::write(fd, ptr, nleft)) <= 0) {
    			if (errno == EINTR)
    				nwritten = 0; /* and call write() again */
    			else
    				return -1; /* error */
    		}
    
    		nleft -= nwritten;
    		ptr   += nwritten;
    	}
    	return n;
    }
    
    
    
    
    // From Steven's Unix Net Programming
    // http://www.kohala.com/start/
    /* Read "n" bytes from a descriptor. */
    ssize_t readn(int fd, void *vptr, size_t n)
    {
    	size_t   nleft;
    	ssize_t  nread;
    	int8_t * ptr;
    
    	ptr = static_cast<int8_t*>(vptr);
    	nleft = n;
    	while (nleft > 0) {
    		if ( (nread = ::read(fd, ptr, nleft)) < 0) {
    			if (errno == EINTR)
    				nread = 0; /* and call read() again */
    			else
    				return -1;
    		}
    		else if (nread == 0)
    			break; /* EOF */
    
    		nleft -= nread;
    		ptr   += nread;
    	}
    	return n - nleft; /* return >= 0 */
    }
    
    
    void rename_main(const string & file, const string & newname)
    {
    	if (newname[0] != '_')
    	{
    		cerr << "INTERNAL ERROR: " __FILE__ << ":" << __LINE__
    		     << "newname argument to rename_main must begin with an underscore to ensure replacement safety" << endl;
    		exit(-2);
    	}
    	assertExists(file);
    	exec( "sed", "-i",
    	      ( "s/int[\\r\\n \\t][\\r\\n \\t]*main(.*)/int " + newname +
    		    "(int argc, char ** argv)/" ).c_str(),
    	      file.c_str() );
    }
    
    vector<string> tokenize(const string & str, char delim)
    {
    	vector<string> args;
    	
    	size_t start = 0;
    	size_t end;
    	for (end = str.find(delim); end != string::npos; end = str.find(delim, start))
    	{
    		args.push_back(str.substr(start, end - start));
    		start = end+1;
    	}
    	args.push_back(str.substr(start, str.size() - start));
    	
    	return args;
    }
    
    
    toole1's avatar
    toole1 committed
    namespace colorize
    {
    const char * BLACK = "\033[39m";
    const char * GREEN = "\033[32m";
    const char * RED   = "\033[31m";
    const bool is_color_enabled = isatty(STDOUT_FILENO);
    
    
    }
    
    
    toole1's avatar
    toole1 committed
    } // namespace util