//
// Util.cc for pekwm
// Copyright (C) 2002-2005 Claes Nasten <pekdon{@}pekdon{.}net>
//
// misc.cc for aewm++
// Copyright (C) 2000 Frank Hale <frankhale@yahoo.com>
// http://sapphire.sourceforge.net/
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#include "../config.h"
#include "Util.hh"
#include <iostream>
#include <sstream>

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef HAVE_SETENV
#include <cstdio>
#include <cstring>
#include <errno.h>
#endif // HAVE_SETENV

using std::cerr;
using std::endl;
using std::string;
using std::vector;
using std::ostringstream;

namespace Util {

//! @brief Fork and execute command with /bin/sh and execlp
void
forkExec(std::string command)
{
	if (command.length() == 0) {
#ifdef DEBUG
		cerr << __FILE__ << "@" << __LINE__ << ": "
				 << "Util::forkExec() *** command length == 0" << endl;
#endif // DEBUG
		return;
	}

	pid_t pid = fork();
	switch (pid) {
	case 0:
		setsid();
		execlp("/bin/sh", "sh", "-c", command.c_str(), (char *) NULL);
		cerr << __FILE__ << "@" << __LINE__ << ": "
				 << "Util::forkExec(" << command << ") execlp failed." << endl;
		exit(1);
	case -1:
		cerr << __FILE__ << "@" << __LINE__ << ": "
				 << "Util::forkExec(" << command << ") fork failed." << endl;
	}
}

//! @brief Determines if the file exists
bool
isFile(const std::string &file)
{
	if (file.size() == 0) {
		return false;
	}

	struct stat stat_buf;
	if (stat(file.c_str(), &stat_buf) == 0) {
		return (S_ISREG(stat_buf.st_mode));
	}

	return false;
}

//! @brief Determines if the file is executable for the current user.
bool
isExecutable(const std::string &file)
{
	if (file.size() == 0) {
#ifdef DEBUG
		cerr << __FILE__ << "@" << __LINE__ << ": "
				 << "Util::isExecutable() *** file length == 0" << endl;
#endif // DEBUG
		return false;
}

	struct stat stat_buf;
	if (!stat(file.c_str(), &stat_buf)) {
		if (stat_buf.st_uid == getuid()) { // user readable and executable
			if ((stat_buf.st_mode&S_IRUSR) && (stat_buf.st_mode&S_IXUSR))
				return true;
		}
		if (getgid() == stat_buf.st_gid) { // group readable and executable
			if ((stat_buf.st_mode&S_IRGRP) && (stat_buf.st_mode&S_IXGRP))
				return true;
		}
		if ((stat_buf.st_mode&S_IROTH) && (stat_buf.st_mode&S_IXOTH)) {
			return true; // other readable and executable
		}
	}

	return false;
}

//! @brief Returns .extension of file
std::string
getFileExt(const std::string &file)
{
	string::size_type pos = file.find_last_of('.');
	if ((pos != string::npos) && (pos < file.size())) {
		return file.substr(pos + 1, file.size() - pos - 1);
	} else {
		return string("");
	}
}

//! @brief Returns dir part of file
std::string
getDir(const std::string &file)
{
	string::size_type pos = file.find_last_of('/');
	if ((pos != string::npos) && (pos < file.size()))
		return file.substr(0, pos);
	else
		return string("");
}

//! @brief Replaces the ~ with the complete homedir path.
void
expandFileName(std::string &file)
{
	if (file.size() > 0) {
		if (file[0] == '~') {
			file.replace(0, 1, getenv("HOME"));
		}
	}
}

//! @brief Split the string str based on separator sep and put into vals
//!
//! This splits the string str into to max_tokens parts and puts in the vector
//! vals. If max is 0 then it'll split it into as many tokens
//! as possible, max defaults to 0.
//! splitString returns the number of tokens it put into vals.
//!
//! @param str String to split
//! @param vals Vector to put split values into
//! @param sep Separators to use when splitting string
//! @param max Maximum number of elements to put into vals (optional)
//! @return Number of tokens inserted into vals
uint
splitString(const std::string &str, std::vector<std::string> &toks,
						const char *sep, uint max)
{
	if (str.size() < 1) {
		return 0;
	}

	uint n = toks.size();
	string::size_type s, e;

	s = str.find_first_not_of(" \t\n");
	for (uint i = 0; ((i < max) || (max == 0)) && (s != string::npos); ++i) {
		e = str.find_first_of(sep, s);

		if ((e != string::npos) && (i < (max - 1))) {
			toks.push_back(str.substr(s, e - s));
		} else if (s < str.size()) {
			toks.push_back(str.substr(s, str.size() - s));
			break;
		} else {
			break;
		}

		s = str.find_first_not_of(sep, e);
	}

	return (toks.size() - n);
}

} // end namespace Util.

//! @brief Inserts or resets the enviornment variable name
#ifndef HAVE_SETENV
int
setenv(const char *name, const char *value, int overwrite)
{
	// invalid parameters
	if ((name == NULL) || (value == NULL)) {
		return -1;
	}

	// don't owerwrite
	if ((overwrite == 0) && (getenv(name) != NULL)) {
		return 0;
	}

	char *str = new char[strlen(name) + strlen(value) + 2];
	if (str == NULL) {
		errno = ENOMEM;
		return -1;
	}

	snprintf(str, strlen(str), "%s=%s", name, value);

	return (putenv(str));
}
#endif // HAVE_SETENV


syntax highlighted by Code2HTML, v. 0.9.1