<commit_before>/**
 * @file
 *
 * @brief Delegate implementation for the `leaf` plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#include <numeric>

#include <kdbassert.h>
#include <kdbease.h>
#include <kdblogger.h>

#include "leaf_delegate.hpp"

using std::accumulate;
using std::make_pair;
using std::pair;
using std::range_error;
using std::string;
using std::tie;

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

namespace elektra
{
using CppKey = kdb::Key;

/**
 * @brief This function splits the given keyset into directory leaves (marked with `DIRECTORY_POSTFIX`) and other keys.
 *
 * @param input The function searches for directory leaves in this key set.
 *
 * @return A pair of key sets, where the first key set contains all directory leaves and the second key set contains all other keys
 */
pair<CppKeySet, CppKeySet> splitDirectoryLeavesOther (CppKeySet const & input)
{
	CppKeySet directoryLeaves;
	CppKeySet other;

	for (auto key : input)
	{
		if (key.getBaseName () == DIRECTORY_POSTFIX)
		{
			directoryLeaves.append (key);
		}
		else
		{
			other.append (key);
		}
	}
	return make_pair (directoryLeaves, other);
}

/**
 * @brief This function removes the directory postfix (`DIRECTORY_POSTFIX`) from the name of all keys in `directoryLeaves`.
 *
 * @pre All key names in `directoryLeaves` must end with `DIRECTORY_POSTFIX`.
 *
 * @param directoryLeaves This parameter contains the keys for which this function removes the directory postfix.
 *
 * @return A copy of the input, where each key name does not end with the directory postfix any more
 */
CppKeySet convertLeavesToDirectories (CppKeySet const & directoryLeaves)
{
	CppKeySet directories;

	for (auto key : directoryLeaves)
	{
		CppKey directory = key.dup ();
		keySetBaseName (*directory, 0);
		directories.append (directory);
	}
	return directories;
}

/**
 * @brief This function returns a modified copy of `child`, where child is directly below `parent`.
 *
 * For example, if `child` has the name `user/parent/level1/level2/level3` and parent has the name `user/parent`, then the function will
 * return a key with the name `user/parent/level1`.
 *
 * @pre The key `child` has to be below `parent`.
 *
 * @param parent This parameter specifies a parent key of `child`.
 * @param keys This variable stores a child key of `parent`.
 *
 * @return A copy of `child` that is directly below `parent`
 */
CppKey convertToDirectChild (CppKey const & parent, CppKey const & child)
{
	ELEKTRA_ASSERT (child.isBelow (parent), "The key `child` is not located below `parent`");

	CppKey directChild = child.dup ();
	while (!directChild.isDirectBelow (parent))
	{
		keySetBaseName (*directChild, 0);
	}
	return directChild;
}

/**
 * @brief This function determines if the given key is an array parent.
 *
 * @param parent This parameter specifies a possible array parent.
 * @param keys This variable stores the key set of `parent`.
 *
 * @retval true If `parent` is the parent key of an array
 * @retval false Otherwise
 */
bool isArrayParent (CppKey const & parent, CppKeySet const & keys)
{
	CppKeySet children = accumulate (keys.begin (), keys.end (), CppKeySet{}, [&parent](CppKeySet collected, CppKey key) {
		if (key.isBelow (parent)) collected.append (key);
		return collected;
	});

	for (auto child : children)
	{
		CppKey directChild = convertToDirectChild (parent, child);
		if (elektraArrayValidateName (*directChild) < 0) return false;
	}

	return true;
}

/**
 * @brief Split `keys` into two key sets, one for array parents and one for all other keys.
 *
 * @param keys This parameter contains the key set this function splits.
 *
 * @return A pair of key sets, where the first key set contains all array parents and the second key set contains all other keys
 */
pair<CppKeySet, CppKeySet> splitArrayParentsOther (CppKeySet const & keys)
{
	CppKeySet arrayParents;
	CppKeySet others;

	keys.rewind ();
	CppKey previous;
	for (previous = keys.next (); keys.next (); previous = keys.current ())
	{
		bool previousIsArray =
			previous.hasMeta ("array") ||
			(keys.current ().isBelow (previous) && keys.current ().getBaseName ()[0] == '#' && isArrayParent (previous, keys));

		(previousIsArray ? arrayParents : others).append (previous);
	}
	(previous.hasMeta ("array") ? arrayParents : others).append (previous);

	ELEKTRA_ASSERT (arrayParents.size () + others.size () == keys.size (),
			"Number of keys in split key sets: %zu ≠ number in given key set %zu", arrayParents.size () + others.size (),
			keys.size ());

	return make_pair (arrayParents, others);
}

/**
 * @brief This function splits `keys` into two key sets, one for array parents and elements, and the other one for all other keys.
 *
 * @param arrayParents This key set contains a (copy) of all array parents of `keys`.
 * @param keys This parameter contains the key set this function splits.
 *
 * @return A pair of key sets, where the first key set contains all array parents and elements,
 *         and the second key set contains all other keys
 */
pair<CppKeySet, CppKeySet> splitArrayOther (CppKeySet const & arrayParents, CppKeySet const & keys)
{
	CppKeySet others = keys.dup ();
	CppKeySet arrays;

	for (auto parent : arrayParents)
	{
		arrays.append (others.cut (parent));
	}

	return make_pair (arrays, others);
}

/**
 * @brief This function increases an array index of the given array element by one.
 *
 * @param parent This key set stores an array parent of `element`. The function will increase the index of `element` that is directly below
 *               this key.
 * @param element This parameter stores an array element.
 *
 * @return A copy of `element`, where the index below `parent` was increased by one
 */
CppKey increaseArrayIndex (CppKey const & parent, CppKey const & element)
{
	CppKey elementNewIndex = convertToDirectChild (parent, element);
	string postfix = elektraKeyGetRelativeName (*element, *elementNewIndex);

	if (elektraArrayIncName (*elementNewIndex))
	{
		throw range_error ("Unable to increase index of key “" + elementNewIndex.getName () + "”");
	}
	elementNewIndex.addName (postfix);

	ELEKTRA_LOG_DEBUG ("New name of “%s” is “%s”", element.getName ().c_str (), elementNewIndex.getName ().c_str ());

	return elementNewIndex;
}

/**
 * @brief Increase the array index of array elements in `arrays` by one.
 *
 * @param parents This parameter contains the array parents for which this function increases the index by one.
 * @param parents This variable stores the arrays elements this function modifies.
 *
 * @return A copy of `arrays`, where all indices specified by `parents` are increased by one.
 */
CppKeySet increaseArrayIndices (CppKeySet const & parents, CppKeySet const & arrays)
{
	CppKeySet arraysIncreasedIndex = arrays.dup ();
	CppKeySet arrayParents = parents.dup ();

	while (CppKey parent = arrayParents.pop ())
	{
		ELEKTRA_LOG_DEBUG ("Increase indices for array parent “%s”", parent.getName ().c_str ());

		arraysIncreasedIndex = accumulate (arraysIncreasedIndex.begin (), arraysIncreasedIndex.end (), CppKeySet{},
						   [&parent](CppKeySet keys, CppKey key) {
							   keys.append (key.isBelow (parent) ? increaseArrayIndex (parent, key) : key);
							   return keys;
						   });
	}

	return arraysIncreasedIndex;
}

/**
 * @brief Split `keys` into two key sets, one for directories (keys without children) and one for all other keys.
 *
 * @param keys This parameter contains the key set this function splits.
 *
 * @return A pair of key sets, where the first key set contains all directories and the second key set contains all leaves
 */
pair<CppKeySet, CppKeySet> splitDirectoriesLeaves (CppKeySet const & keys)
{
	CppKeySet leaves;
	CppKeySet directories;

	keys.rewind ();
	CppKey previous;
	for (previous = keys.next (); keys.next (); previous = keys.current ())
	{
		if (keys.current ().isBelow (previous))
		{
			directories.append (previous);
		}
		else
		{
			leaves.append (previous);
		}
	}
	leaves.append (previous);

	return make_pair (directories, leaves);
}

/**
 * @brief Convert all keys in `directories` to an empty key and a leaf key containing the data of the old key.
 *
 * @param directories This parameter contains a set of directory keys this function converts.
 *
 * @return A key set containing only empty directory keys and corresponding leaf keys storing the values of the old directory keys
 */
CppKeySet convertDirectoriesToLeaves (CppKeySet const & directories)
{
	CppKeySet directoryLeaves;

	for (auto directory : directories)
	{
		CppKey emptyDirectory{ directory.getName (), KS_END };
		CppKey leaf = directory.dup ();
		leaf.addBaseName (DIRECTORY_POSTFIX);
		directoryLeaves.append (leaf);
		directoryLeaves.append (emptyDirectory);
	}

	return directoryLeaves;
}

// -- Class --------------------------------------------------------------------------------------------------------------------------------

/**
 * @brief This constructor creates a new delegate object used by the `leaf` plugin
 *
 * @param config This key set contains configuration values provided by the `leaf` plugin
 */
LeafDelegate::LeafDelegate (CppKeySet config ELEKTRA_UNUSED)
{
}

/**
 * @brief This method converts all leaf keys in the given key set to directory keys.
 *
 * @param keys This parameter specifies the key set this function converts.
 *
 * @retval ELEKTRA_PLUGIN_STATUS_SUCCESS If the plugin converted any value in the given key set
 * @retval ELEKTRA_PLUGIN_STATUS_NO_UPDATE If the plugin did not update `keys`
 */
int LeafDelegate::convertToDirectories (CppKeySet & keys)
{
	CppKeySet directoryLeaves;
	CppKeySet nonDirectoryLeaves;
	tie (directoryLeaves, nonDirectoryLeaves) = splitDirectoryLeavesOther (keys);

	bool status = directoryLeaves.size () > 0 ? ELEKTRA_PLUGIN_STATUS_SUCCESS : ELEKTRA_PLUGIN_STATUS_NO_UPDATE;

	auto directories = convertLeavesToDirectories (directoryLeaves);

	keys.clear ();
	keys.append (nonDirectoryLeaves);
	keys.append (directories);

	return status;
}

/**
 * @brief This method converts all directory keys in the given key set to leaf keys.
 *
 * @param keys This parameter specifies the key set this function converts.
 *
 * @retval ELEKTRA_PLUGIN_STATUS_SUCCESS If the plugin converted any value in the given key set
 * @retval ELEKTRA_PLUGIN_STATUS_NO_UPDATE If the plugin did not update `keys`
 */
int LeafDelegate::convertToLeaves (CppKeySet & keys)
{
	CppKeySet directories;
	CppKeySet leaves;
	tie (directories, leaves) = splitDirectoriesLeaves (keys);
	bool status = directories.size () > 0 ? ELEKTRA_PLUGIN_STATUS_SUCCESS : ELEKTRA_PLUGIN_STATUS_NO_UPDATE;

	auto directoryLeaves = convertDirectoriesToLeaves (directories);

	keys.clear ();
	keys.append (directoryLeaves);
	keys.append (leaves);

	return status;
}

} // end namespace elektra
<commit_msg>Leaf: Add function to convert array parents<commit_after>/**
 * @file
 *
 * @brief Delegate implementation for the `leaf` plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#include <numeric>

#include <kdbassert.h>
#include <kdbease.h>
#include <kdblogger.h>

#include "leaf_delegate.hpp"

using std::accumulate;
using std::make_pair;
using std::pair;
using std::range_error;
using std::string;
using std::tie;

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

namespace elektra
{
using CppKey = kdb::Key;

/**
 * @brief This function splits the given keyset into directory leaves (marked with `DIRECTORY_POSTFIX`) and other keys.
 *
 * @param input The function searches for directory leaves in this key set.
 *
 * @return A pair of key sets, where the first key set contains all directory leaves and the second key set contains all other keys
 */
pair<CppKeySet, CppKeySet> splitDirectoryLeavesOther (CppKeySet const & input)
{
	CppKeySet directoryLeaves;
	CppKeySet other;

	for (auto key : input)
	{
		if (key.getBaseName () == DIRECTORY_POSTFIX)
		{
			directoryLeaves.append (key);
		}
		else
		{
			other.append (key);
		}
	}
	return make_pair (directoryLeaves, other);
}

/**
 * @brief This function removes the directory postfix (`DIRECTORY_POSTFIX`) from the name of all keys in `directoryLeaves`.
 *
 * @pre All key names in `directoryLeaves` must end with `DIRECTORY_POSTFIX`.
 *
 * @param directoryLeaves This parameter contains the keys for which this function removes the directory postfix.
 *
 * @return A copy of the input, where each key name does not end with the directory postfix any more
 */
CppKeySet convertLeavesToDirectories (CppKeySet const & directoryLeaves)
{
	CppKeySet directories;

	for (auto key : directoryLeaves)
	{
		CppKey directory = key.dup ();
		keySetBaseName (*directory, 0);
		directories.append (directory);
	}
	return directories;
}

/**
 * @brief This function returns a modified copy of `child`, where child is directly below `parent`.
 *
 * For example, if `child` has the name `user/parent/level1/level2/level3` and parent has the name `user/parent`, then the function will
 * return a key with the name `user/parent/level1`.
 *
 * @pre The key `child` has to be below `parent`.
 *
 * @param parent This parameter specifies a parent key of `child`.
 * @param keys This variable stores a child key of `parent`.
 *
 * @return A copy of `child` that is directly below `parent`
 */
CppKey convertToDirectChild (CppKey const & parent, CppKey const & child)
{
	ELEKTRA_ASSERT (child.isBelow (parent), "The key `child` is not located below `parent`");

	CppKey directChild = child.dup ();
	while (!directChild.isDirectBelow (parent))
	{
		keySetBaseName (*directChild, 0);
	}
	return directChild;
}

/**
 * @brief This function determines if the given key is an array parent.
 *
 * @param parent This parameter specifies a possible array parent.
 * @param keys This variable stores the key set of `parent`.
 *
 * @retval true If `parent` is the parent key of an array
 * @retval false Otherwise
 */
bool isArrayParent (CppKey const & parent, CppKeySet const & keys)
{
	CppKeySet children = accumulate (keys.begin (), keys.end (), CppKeySet{}, [&parent](CppKeySet collected, CppKey key) {
		if (key.isBelow (parent)) collected.append (key);
		return collected;
	});

	for (auto child : children)
	{
		CppKey directChild = convertToDirectChild (parent, child);
		if (elektraArrayValidateName (*directChild) < 0) return false;
	}

	return true;
}

/**
 * @brief Split `keys` into two key sets, one for array parents and one for all other keys.
 *
 * @param keys This parameter contains the key set this function splits.
 *
 * @return A pair of key sets, where the first key set contains all array parents and the second key set contains all other keys
 */
pair<CppKeySet, CppKeySet> splitArrayParentsOther (CppKeySet const & keys)
{
	CppKeySet arrayParents;
	CppKeySet others;

	keys.rewind ();
	CppKey previous;
	for (previous = keys.next (); keys.next (); previous = keys.current ())
	{
		bool previousIsArray =
			previous.hasMeta ("array") ||
			(keys.current ().isBelow (previous) && keys.current ().getBaseName ()[0] == '#' && isArrayParent (previous, keys));

		(previousIsArray ? arrayParents : others).append (previous);
	}
	(previous.hasMeta ("array") ? arrayParents : others).append (previous);

	ELEKTRA_ASSERT (arrayParents.size () + others.size () == keys.size (),
			"Number of keys in split key sets: %zu ≠ number in given key set %zu", arrayParents.size () + others.size (),
			keys.size ());

	return make_pair (arrayParents, others);
}

/**
 * @brief This function splits `keys` into two key sets, one for array parents and elements, and the other one for all other keys.
 *
 * @param arrayParents This key set contains a (copy) of all array parents of `keys`.
 * @param keys This parameter contains the key set this function splits.
 *
 * @return A pair of key sets, where the first key set contains all array parents and elements,
 *         and the second key set contains all other keys
 */
pair<CppKeySet, CppKeySet> splitArrayOther (CppKeySet const & arrayParents, CppKeySet const & keys)
{
	CppKeySet others = keys.dup ();
	CppKeySet arrays;

	for (auto parent : arrayParents)
	{
		arrays.append (others.cut (parent));
	}

	return make_pair (arrays, others);
}

/**
 * @brief This function increases an array index of the given array element by one.
 *
 * @param parent This key set stores an array parent of `element`. The function will increase the index of `element` that is directly below
 *               this key.
 * @param element This parameter stores an array element.
 *
 * @return A copy of `element`, where the index below `parent` was increased by one
 */
CppKey increaseArrayIndex (CppKey const & parent, CppKey const & element)
{
	CppKey elementNewIndex = convertToDirectChild (parent, element);
	string postfix = elektraKeyGetRelativeName (*element, *elementNewIndex);

	if (elektraArrayIncName (*elementNewIndex))
	{
		throw range_error ("Unable to increase index of key “" + elementNewIndex.getName () + "”");
	}
	elementNewIndex.addName (postfix);

	ELEKTRA_LOG_DEBUG ("New name of “%s” is “%s”", element.getName ().c_str (), elementNewIndex.getName ().c_str ());

	return elementNewIndex;
}

/**
 * @brief Increase the array index of array elements in `arrays` by one.
 *
 * @param parents This parameter contains the array parents for which this function increases the index by one.
 * @param parents This variable stores the arrays elements this function modifies.
 *
 * @return A copy of `arrays`, where all indices specified by `parents` are increased by one.
 */
CppKeySet increaseArrayIndices (CppKeySet const & parents, CppKeySet const & arrays)
{
	CppKeySet arraysIncreasedIndex = arrays.dup ();
	CppKeySet arrayParents = parents.dup ();

	while (CppKey parent = arrayParents.pop ())
	{
		ELEKTRA_LOG_DEBUG ("Increase indices for array parent “%s”", parent.getName ().c_str ());

		arraysIncreasedIndex = accumulate (arraysIncreasedIndex.begin (), arraysIncreasedIndex.end (), CppKeySet{},
						   [&parent](CppKeySet keys, CppKey key) {
							   keys.append (key.isBelow (parent) ? increaseArrayIndex (parent, key) : key);
							   return keys;
						   });
	}

	return arraysIncreasedIndex;
}

/**
 * @brief Split `keys` into two key sets, one for directories (keys without children) and one for all other keys.
 *
 * @param keys This parameter contains the key set this function splits.
 *
 * @return A pair of key sets, where the first key set contains all directories and the second key set contains all leaves
 */
pair<CppKeySet, CppKeySet> splitDirectoriesLeaves (CppKeySet const & keys)
{
	CppKeySet leaves;
	CppKeySet directories;

	keys.rewind ();
	CppKey previous;
	for (previous = keys.next (); keys.next (); previous = keys.current ())
	{
		if (keys.current ().isBelow (previous))
		{
			directories.append (previous);
		}
		else
		{
			leaves.append (previous);
		}
	}
	leaves.append (previous);

	return make_pair (directories, leaves);
}

/**
 * @brief Convert all keys in `parents` to an empty array parent and an array element with index `#0` storing the data of the old key.
 *
 * @param parents This parameter contains the set of array parent this function converts.
 *
 * @return A key set containing only empty array parents and corresponding array elements storing the values of the old array parent
 */
CppKeySet convertArrayParentsToLeaves (CppKeySet const & parents)
{
	CppKeySet converted;

	for (auto parent : parents)
	{
		CppKey directory{ parent.getName (), KS_END };
		CppKey leaf = parent.dup ();
		leaf.addBaseName ("#0");
		converted.append (directory);
		converted.append (leaf);
	}

	return converted;
}

/**
 * @brief Convert all keys in `directories` to an empty key and a leaf key containing the data of the old key.
 *
 * @param directories This parameter contains a set of directory keys this function converts.
 *
 * @return A key set containing only empty directory keys and corresponding leaf keys storing the values of the old directory keys
 */
CppKeySet convertDirectoriesToLeaves (CppKeySet const & directories)
{
	CppKeySet directoryLeaves;

	for (auto directory : directories)
	{
		CppKey emptyDirectory{ directory.getName (), KS_END };
		CppKey leaf = directory.dup ();
		leaf.addBaseName (DIRECTORY_POSTFIX);
		directoryLeaves.append (leaf);
		directoryLeaves.append (emptyDirectory);
	}

	return directoryLeaves;
}

// -- Class --------------------------------------------------------------------------------------------------------------------------------

/**
 * @brief This constructor creates a new delegate object used by the `leaf` plugin
 *
 * @param config This key set contains configuration values provided by the `leaf` plugin
 */
LeafDelegate::LeafDelegate (CppKeySet config ELEKTRA_UNUSED)
{
}

/**
 * @brief This method converts all leaf keys in the given key set to directory keys.
 *
 * @param keys This parameter specifies the key set this function converts.
 *
 * @retval ELEKTRA_PLUGIN_STATUS_SUCCESS If the plugin converted any value in the given key set
 * @retval ELEKTRA_PLUGIN_STATUS_NO_UPDATE If the plugin did not update `keys`
 */
int LeafDelegate::convertToDirectories (CppKeySet & keys)
{
	CppKeySet directoryLeaves;
	CppKeySet nonDirectoryLeaves;
	tie (directoryLeaves, nonDirectoryLeaves) = splitDirectoryLeavesOther (keys);

	bool status = directoryLeaves.size () > 0 ? ELEKTRA_PLUGIN_STATUS_SUCCESS : ELEKTRA_PLUGIN_STATUS_NO_UPDATE;

	auto directories = convertLeavesToDirectories (directoryLeaves);

	keys.clear ();
	keys.append (nonDirectoryLeaves);
	keys.append (directories);

	return status;
}

/**
 * @brief This method converts all directory keys in the given key set to leaf keys.
 *
 * @param keys This parameter specifies the key set this function converts.
 *
 * @retval ELEKTRA_PLUGIN_STATUS_SUCCESS If the plugin converted any value in the given key set
 * @retval ELEKTRA_PLUGIN_STATUS_NO_UPDATE If the plugin did not update `keys`
 */
int LeafDelegate::convertToLeaves (CppKeySet & keys)
{
	CppKeySet directories;
	CppKeySet leaves;
	tie (directories, leaves) = splitDirectoriesLeaves (keys);
	bool status = directories.size () > 0 ? ELEKTRA_PLUGIN_STATUS_SUCCESS : ELEKTRA_PLUGIN_STATUS_NO_UPDATE;

	auto directoryLeaves = convertDirectoriesToLeaves (directories);

	keys.clear ();
	keys.append (directoryLeaves);
	keys.append (leaves);

	return status;
}

} // end namespace elektra
<|endoftext|>


<commit_before>// mail-qman - deliver mail messages from the queue

// The spool directory has the following structure:
// * pid/<pid> - message files under construction
// * mess/<inumber> - message files
// * todo/<message inumber> - envelope files
// * notify - a UNIX socket that receives an <inumber> when a message
//   is added to the spool

#include "libutil.h"
#include "shutil.h"
#include "xsys.h"

#include <fcntl.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>

#include <stdexcept>
#include <string>
#include <thread>

using std::string;
using std::thread;

extern char **environ;

static bool alt;

class spool_reader
{
  string spooldir_;
  int notifyfd_;
  struct sockaddr_un notify_sun_;

public:
  spool_reader(const string &spooldir) : spooldir_(spooldir)
  {
    // Create notification socket
    notifyfd_ = socket(AF_UNIX, alt ? SOCK_DGRAM_UNORDERED : SOCK_DGRAM, 0);
    if (notifyfd_ < 0)
      edie("socket failed");
    struct sockaddr_un sun{};
    sun.sun_family = AF_UNIX;
    snprintf(sun.sun_path, sizeof sun.sun_path, "%s/notify", spooldir.c_str());

    // Normally we would just unlink(sun.sun_path), but since there's
    // no way to kill mail-qman on xv6 right now, if it exists, it
    // means this is a duplicate.
    struct stat st;
    if (stat(sun.sun_path, &st) == 0)
      die("%s exists; mail-qman already running?", sun.sun_path);

    unlink(sun.sun_path);
    if (bind(notifyfd_, (struct sockaddr*)&sun, SUN_LEN(&sun)) < 0)
      edie("bind failed");

    notify_sun_ = sun;
  }

  string dequeue()
  {
    char buf[256];
    ssize_t r = recv(notifyfd_, buf, sizeof buf, 0);
    if (r < 0)
      edie("recv failed");
    return {buf, (size_t)r};
  }

  string get_recipient(const string &id)
  {
    char path[256];
    snprintf(path, sizeof path, "%s/todo/%s", spooldir_.c_str(), id.c_str());
    int fd = open(path, O_RDONLY|O_CLOEXEC|(alt ? O_ANYFD : 0));
    if (fd < 0)
      edie("open %s failed", path);
    struct stat st;
    // We don't use "alt" here, even though this is an alternate
    // interface, because this commutes regardless.  Passing
    // STAT_OMIT_NLINK is just for performance.
    // XXX Maybe we should use a resizing read rather than fstat.
    if (fstatx(fd, &st, STAT_OMIT_NLINK) < 0)
      edie("fstat %s failed", path);
    string res(st.st_size, 0);
    if (readall(fd, &res.front(), res.size()) != res.size())
      edie("readall %s failed", path);
    close(fd);
    return res;
  }

  int open_message(const string &id)
  {
    char path[256];
    snprintf(path, sizeof path, "%s/mess/%s", spooldir_.c_str(), id.c_str());
    int fd = open(path, O_RDONLY|O_CLOEXEC|(alt ? O_ANYFD : 0));
    if (fd < 0)
      edie("open %s failed", path);
    return fd;
  }

  void remove(const string &id)
  {
    string x;
    x.append(spooldir_).append("/todo/").append(id);
    unlink(x.c_str());
    x.clear();
    x.append(spooldir_).append("/mess/").append(id);
    unlink(x.c_str());
  }

  void exit_others(int mycpu, int nthread)
  {
    // xv6 doesn't have an easy way to kill processes, so cascade the
    // exit message to all other threads. We have to affinitize
    // ourselves around in case socket load balancing is off.
    int notifyfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (notifyfd < 0)
      edie("%s: socket failed", __func__);

    const char *killmsg = "EXIT2";
    for (int i = 0; i < nthread; ++i) {
      if (i == mycpu)
        continue;
      setaffinity(i);
      if (sendto(notifyfd, killmsg, strlen(killmsg), 0,
                 (struct sockaddr*)&notify_sun_, SUN_LEN(&notify_sun_)) < 0)
        edie("%s: sendto failed", __func__);
    }

    close(notifyfd);

    setaffinity(mycpu);
  }
};

static void
deliver(const char *mailroot, int msgfd, const string &recipient)
{
  const char *argv[] = {"./mail-deliver", mailroot, recipient.c_str(), nullptr};

  pid_t pid;
#if defined(XV6_USER)
  // xv6 doesn't define errno.
  int errno = 0;
#endif
  if (alt) {
    posix_spawn_file_actions_t actions;
    if ((errno = posix_spawn_file_actions_init(&actions)))
      edie("posix_spawn_file_actions_init failed");
    if ((errno = posix_spawn_file_actions_adddup2(&actions, msgfd, 0)))
      edie("posix_spawn_file_actions_adddup2 failed");
    if ((errno = posix_spawn(&pid, argv[0], &actions, nullptr,
                             const_cast<char *const*>(argv), environ)))
      edie("posix_spawn failed");
    if ((errno = posix_spawn_file_actions_destroy(&actions)))
      edie("posix_spawn_file_actions_destroy failed");
  } else {
    pid = fork();
    if (pid < 0)
      edie("fork failed");
    if (pid == 0) {
      dup2(msgfd, 0);
      execv(argv[0], const_cast<char *const*>(argv));
      edie("execv %s failed", argv[0]);
    }
  }

  int status;
  if (waitpid(pid, &status, 0) < 0)
    edie("waitpid failed");
  if (!WIFEXITED(status) || WEXITSTATUS(status))
    die("deliver failed: status %d", status);
}

static void
do_process(spool_reader *spool, const char *mailroot, int nthread, int cpu)
{
  while (true) {
    string id = spool->dequeue();
    if (id == "EXIT") {
      spool->exit_others(cpu, nthread);
      return;
    }
    if (id == "EXIT2")
      return;
    string recip = spool->get_recipient(id);
    int msgfd = spool->open_message(id);
    deliver(mailroot, msgfd, recip);
    close(msgfd);
    spool->remove(id);
  }
}

static void
usage(const char *argv0)
{
  fprintf(stderr, "Usage: %s [options] spooldir mailroot nthread\n", argv0);
  fprintf(stderr, "  -a none   Use regular APIs (default)\n");
  fprintf(stderr, "     all    Use alternate APIs\n");
  exit(2);
}

int
main(int argc, char **argv)
{
  int opt;
  while ((opt = getopt(argc, argv, "a:")) != -1) {
    switch (opt) {
    case 'a':
      if (strcmp(optarg, "all") == 0)
        alt = true;
      else if (strcmp(optarg, "none") == 0)
        alt = false;
      else
        usage(argv[0]);
      break;
    default:
      usage(argv[0]);
    }
  }

  if (argc - optind != 3)
    usage(argv[0]);

  const char *spooldir = argv[optind];
  const char *mailroot = argv[optind+1];
  int nthread = atoi(argv[optind+2]);
  if (nthread <= 0)
    usage(argv[0]);

  spool_reader reader{spooldir};

  thread *threads = new thread[nthread];

  for (int i = 0; i < nthread; ++i) {
    setaffinity(i);
    threads[i] = std::move(thread(do_process, &reader, mailroot, nthread, i));
  }

  for (int i = 0; i < nthread; ++i)
    threads[i].join();
}
<commit_msg>mail-qman: Restructure delivery into a class<commit_after>// mail-qman - deliver mail messages from the queue

// The spool directory has the following structure:
// * pid/<pid> - message files under construction
// * mess/<inumber> - message files
// * todo/<message inumber> - envelope files
// * notify - a UNIX socket that receives an <inumber> when a message
//   is added to the spool

#include "libutil.h"
#include "shutil.h"
#include "xsys.h"

#include <fcntl.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>

#include <stdexcept>
#include <string>
#include <thread>

using std::string;
using std::thread;

extern char **environ;

static bool alt;

class spool_reader
{
  string spooldir_;
  int notifyfd_;
  struct sockaddr_un notify_sun_;

public:
  spool_reader(const string &spooldir) : spooldir_(spooldir)
  {
    // Create notification socket
    notifyfd_ = socket(AF_UNIX, alt ? SOCK_DGRAM_UNORDERED : SOCK_DGRAM, 0);
    if (notifyfd_ < 0)
      edie("socket failed");
    struct sockaddr_un sun{};
    sun.sun_family = AF_UNIX;
    snprintf(sun.sun_path, sizeof sun.sun_path, "%s/notify", spooldir.c_str());

    // Normally we would just unlink(sun.sun_path), but since there's
    // no way to kill mail-qman on xv6 right now, if it exists, it
    // means this is a duplicate.
    struct stat st;
    if (stat(sun.sun_path, &st) == 0)
      die("%s exists; mail-qman already running?", sun.sun_path);

    unlink(sun.sun_path);
    if (bind(notifyfd_, (struct sockaddr*)&sun, SUN_LEN(&sun)) < 0)
      edie("bind failed");

    notify_sun_ = sun;
  }

  string dequeue()
  {
    char buf[256];
    ssize_t r = recv(notifyfd_, buf, sizeof buf, 0);
    if (r < 0)
      edie("recv failed");
    return {buf, (size_t)r};
  }

  string get_recipient(const string &id)
  {
    char path[256];
    snprintf(path, sizeof path, "%s/todo/%s", spooldir_.c_str(), id.c_str());
    int fd = open(path, O_RDONLY|O_CLOEXEC|(alt ? O_ANYFD : 0));
    if (fd < 0)
      edie("open %s failed", path);
    struct stat st;
    // We don't use "alt" here, even though this is an alternate
    // interface, because this commutes regardless.  Passing
    // STAT_OMIT_NLINK is just for performance.
    // XXX Maybe we should use a resizing read rather than fstat.
    if (fstatx(fd, &st, STAT_OMIT_NLINK) < 0)
      edie("fstat %s failed", path);
    string res(st.st_size, 0);
    if (readall(fd, &res.front(), res.size()) != res.size())
      edie("readall %s failed", path);
    close(fd);
    return res;
  }

  int open_message(const string &id)
  {
    char path[256];
    snprintf(path, sizeof path, "%s/mess/%s", spooldir_.c_str(), id.c_str());
    int fd = open(path, O_RDONLY|O_CLOEXEC|(alt ? O_ANYFD : 0));
    if (fd < 0)
      edie("open %s failed", path);
    return fd;
  }

  void remove(const string &id)
  {
    string x;
    x.append(spooldir_).append("/todo/").append(id);
    unlink(x.c_str());
    x.clear();
    x.append(spooldir_).append("/mess/").append(id);
    unlink(x.c_str());
  }

  void exit_others(int mycpu, int nthread)
  {
    // xv6 doesn't have an easy way to kill processes, so cascade the
    // exit message to all other threads. We have to affinitize
    // ourselves around in case socket load balancing is off.
    int notifyfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (notifyfd < 0)
      edie("%s: socket failed", __func__);

    const char *killmsg = "EXIT2";
    for (int i = 0; i < nthread; ++i) {
      if (i == mycpu)
        continue;
      setaffinity(i);
      if (sendto(notifyfd, killmsg, strlen(killmsg), 0,
                 (struct sockaddr*)&notify_sun_, SUN_LEN(&notify_sun_)) < 0)
        edie("%s: sendto failed", __func__);
    }

    close(notifyfd);

    setaffinity(mycpu);
  }
};

class deliverer
{
  pid_t pid_;
  string mailroot_;

  void start_child(const char *argv[], int stdin, int stdout)
  {
#if defined(XV6_USER)
    // xv6 doesn't define errno.
    int errno = 0;
#endif
    if (alt) {
      posix_spawn_file_actions_t actions;
      if ((errno = posix_spawn_file_actions_init(&actions)))
        edie("posix_spawn_file_actions_init failed");
      if (stdin >= 0)
        if ((errno = posix_spawn_file_actions_adddup2(&actions, stdin, 0)))
          edie("posix_spawn_file_actions_adddup2 failed");
      if (stdout >= 0)
        if ((errno = posix_spawn_file_actions_adddup2(&actions, stdout, 1)))
          edie("posix_spawn_file_actions_adddup2 failed");
      if ((errno = posix_spawn(&pid_, argv[0], &actions, nullptr,
                               const_cast<char *const*>(argv), environ)))
        edie("posix_spawn failed");
      if ((errno = posix_spawn_file_actions_destroy(&actions)))
        edie("posix_spawn_file_actions_destroy failed");
    } else {
      pid_ = fork();
      if (pid_ < 0)
        edie("fork failed");
      if (pid_ == 0) {
        // Note that this doesn't handle the case where stdin/stdout are
        // 0/1 and have O_CLOEXEC set, but that never happens here.
        if (stdin >= 0 && dup2(stdin, 0) < 0)
          edie("dup2 stdin failed");
        if (stdout >= 0 && dup2(stdout, 1) < 0)
          edie("dup2 stdout failed");
        execv(argv[0], const_cast<char *const*>(argv));
        edie("execv %s failed", argv[0]);
      }
    }
  }

  void wait_child()
  {
    int status;
    if (waitpid(pid_, &status, 0) < 0)
      edie("waitpid failed");
    if (!WIFEXITED(status) || WEXITSTATUS(status))
      die("deliver failed: status %d", status);
    pid_ = 0;
  }

public:
  deliverer(const string &mailroot)
    : pid_(0), mailroot_(mailroot) { }

  void
  deliver(const string &recipient, int msgfd)
  {
    const char *argv[] = {"./mail-deliver", mailroot_.c_str(),
                          recipient.c_str(), nullptr};
    start_child(argv, msgfd, -1);
    wait_child();
  }
};

static void
do_process(spool_reader *spool, const string &mailroot, int nthread, int cpu)
{
  deliverer d{mailroot};
  while (true) {
    string id = spool->dequeue();
    if (id == "EXIT") {
      spool->exit_others(cpu, nthread);
      return;
    }
    if (id == "EXIT2")
      return;
    string recip = spool->get_recipient(id);
    int msgfd = spool->open_message(id);
    d.deliver(recip, msgfd);
    close(msgfd);
    spool->remove(id);
  }
}

static void
usage(const char *argv0)
{
  fprintf(stderr, "Usage: %s [options] spooldir mailroot nthread\n", argv0);
  fprintf(stderr, "  -a none   Use regular APIs (default)\n");
  fprintf(stderr, "     all    Use alternate APIs\n");
  exit(2);
}

int
main(int argc, char **argv)
{
  int opt;
  while ((opt = getopt(argc, argv, "a:")) != -1) {
    switch (opt) {
    case 'a':
      if (strcmp(optarg, "all") == 0)
        alt = true;
      else if (strcmp(optarg, "none") == 0)
        alt = false;
      else
        usage(argv[0]);
      break;
    default:
      usage(argv[0]);
    }
  }

  if (argc - optind != 3)
    usage(argv[0]);

  const char *spooldir = argv[optind];
  const char *mailroot = argv[optind+1];
  int nthread = atoi(argv[optind+2]);
  if (nthread <= 0)
    usage(argv[0]);

  spool_reader reader{spooldir};

  thread *threads = new thread[nthread];

  for (int i = 0; i < nthread; ++i) {
    setaffinity(i);
    threads[i] = std::move(thread(do_process, &reader, mailroot, nthread, i));
  }

  for (int i = 0; i < nthread; ++i)
    threads[i].join();
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** Copyright (C) 2015 Brian McGillion and Hugues Delorme
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "vcscommand.h"
#include "vcsbaseplugin.h"

#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/icore.h>
#include <vcsbase/vcsoutputwindow.h>
#include <utils/fileutils.h>
#include <utils/synchronousprocess.h>
#include <utils/runextensions.h>
#include <utils/qtcassert.h>

#include <QDebug>
#include <QProcess>
#include <QProcessEnvironment>
#include <QFuture>
#include <QFutureWatcher>
#include <QtConcurrentRun>
#include <QFileInfo>
#include <QCoreApplication>
#include <QVariant>
#include <QStringList>
#include <QTextCodec>
#include <QMutex>

namespace VcsBase {

VcsCommand::VcsCommand(const QString &workingDirectory,
                       const QProcessEnvironment &environment) :
    Core::ShellCommand(workingDirectory, environment),
    m_preventRepositoryChanged(false)
{
    setOutputProxyFactory([]() -> Utils::OutputProxy * {
                              auto proxy = new Utils::OutputProxy;
                              VcsOutputWindow *outputWindow = VcsOutputWindow::instance();

                              connect(proxy, &Utils::OutputProxy::append,
                                      outputWindow, [](const QString &txt) { VcsOutputWindow::append(txt); },
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendSilently,
                                      outputWindow, &VcsOutputWindow::appendSilently,
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendError,
                                      outputWindow, &VcsOutputWindow::appendError,
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendCommand,
                                      outputWindow, &VcsOutputWindow::appendCommand,
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendMessage,
                                      outputWindow, &VcsOutputWindow::appendMessage,
                                      Qt::QueuedConnection);

                              return proxy;
                          });
}

const QProcessEnvironment VcsCommand::processEnvironment() const
{
    QProcessEnvironment env = Core::ShellCommand::processEnvironment();
    VcsBasePlugin::setProcessEnvironment(&env, flags() & ForceCLocale, VcsBasePlugin::sshPrompt());
    return env;
}

Utils::SynchronousProcessResponse VcsCommand::runCommand(const Utils::FileName &binary,
                                                         const QStringList &arguments, int timeoutS,
                                                         Utils::ExitCodeInterpreter *interpreter)
{
    Utils::SynchronousProcessResponse response
            = Core::ShellCommand::runCommand(binary, arguments, timeoutS, interpreter);
    emitRepositoryChanged();
    return response;
}

bool VcsCommand::runFullySynchronous(const Utils::FileName &binary, const QStringList &arguments,
                                     int timeoutS, QByteArray *outputData, QByteArray *errorData)
{
    bool result = Core::ShellCommand::runFullySynchronous(binary, arguments, timeoutS,
                                                          outputData, errorData);
    emitRepositoryChanged();
    return result;
}

void VcsCommand::emitRepositoryChanged()
{
    if (m_preventRepositoryChanged || !(flags() & VcsCommand::ExpectRepoChanges))
        return;
    // TODO tell the document manager that the directory now received all expected changes
    // Core::DocumentManager::unexpectDirectoryChange(d->m_workingDirectory);
    Core::VcsManager::emitRepositoryChanged(workingDirectory());
}

unsigned VcsCommand::processFlags() const
{
    unsigned processFlags = 0;
    if (!VcsBasePlugin::sshPrompt().isEmpty() && (flags() & SshPasswordPrompt))
        processFlags |= Utils::SynchronousProcess::UnixTerminalDisabled;
    return processFlags;
}

void VcsCommand::coreAboutToClose()
{
    m_preventRepositoryChanged = true;
    abort();
}

} // namespace VcsBase
<commit_msg>Vcs: Fix compilation for gcc 4.7.3<commit_after>/**************************************************************************
**
** Copyright (C) 2015 Brian McGillion and Hugues Delorme
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "vcscommand.h"
#include "vcsbaseplugin.h"

#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/icore.h>
#include <vcsbase/vcsoutputwindow.h>
#include <utils/fileutils.h>
#include <utils/synchronousprocess.h>
#include <utils/runextensions.h>
#include <utils/qtcassert.h>

#include <QDebug>
#include <QProcess>
#include <QProcessEnvironment>
#include <QFuture>
#include <QFutureWatcher>
#include <QtConcurrentRun>
#include <QFileInfo>
#include <QCoreApplication>
#include <QVariant>
#include <QStringList>
#include <QTextCodec>
#include <QMutex>

namespace VcsBase {

VcsCommand::VcsCommand(const QString &workingDirectory,
                       const QProcessEnvironment &environment) :
    Core::ShellCommand(workingDirectory, environment),
    m_preventRepositoryChanged(false)
{
    setOutputProxyFactory([this]() -> Utils::OutputProxy * {
                              auto proxy = new Utils::OutputProxy;
                              VcsOutputWindow *outputWindow = VcsOutputWindow::instance();

                              connect(proxy, &Utils::OutputProxy::append,
                                      outputWindow, [](const QString &txt) { VcsOutputWindow::append(txt); },
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendSilently,
                                      outputWindow, &VcsOutputWindow::appendSilently,
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendError,
                                      outputWindow, &VcsOutputWindow::appendError,
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendCommand,
                                      outputWindow, &VcsOutputWindow::appendCommand,
                                      Qt::QueuedConnection);
                              connect(proxy, &Utils::OutputProxy::appendMessage,
                                      outputWindow, &VcsOutputWindow::appendMessage,
                                      Qt::QueuedConnection);

                              return proxy;
                          });
}

const QProcessEnvironment VcsCommand::processEnvironment() const
{
    QProcessEnvironment env = Core::ShellCommand::processEnvironment();
    VcsBasePlugin::setProcessEnvironment(&env, flags() & ForceCLocale, VcsBasePlugin::sshPrompt());
    return env;
}

Utils::SynchronousProcessResponse VcsCommand::runCommand(const Utils::FileName &binary,
                                                         const QStringList &arguments, int timeoutS,
                                                         Utils::ExitCodeInterpreter *interpreter)
{
    Utils::SynchronousProcessResponse response
            = Core::ShellCommand::runCommand(binary, arguments, timeoutS, interpreter);
    emitRepositoryChanged();
    return response;
}

bool VcsCommand::runFullySynchronous(const Utils::FileName &binary, const QStringList &arguments,
                                     int timeoutS, QByteArray *outputData, QByteArray *errorData)
{
    bool result = Core::ShellCommand::runFullySynchronous(binary, arguments, timeoutS,
                                                          outputData, errorData);
    emitRepositoryChanged();
    return result;
}

void VcsCommand::emitRepositoryChanged()
{
    if (m_preventRepositoryChanged || !(flags() & VcsCommand::ExpectRepoChanges))
        return;
    // TODO tell the document manager that the directory now received all expected changes
    // Core::DocumentManager::unexpectDirectoryChange(d->m_workingDirectory);
    Core::VcsManager::emitRepositoryChanged(workingDirectory());
}

unsigned VcsCommand::processFlags() const
{
    unsigned processFlags = 0;
    if (!VcsBasePlugin::sshPrompt().isEmpty() && (flags() & SshPasswordPrompt))
        processFlags |= Utils::SynchronousProcess::UnixTerminalDisabled;
    return processFlags;
}

void VcsCommand::coreAboutToClose()
{
    m_preventRepositoryChanged = true;
    abort();
}

} // namespace VcsBase
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fldedt.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2006-08-14 17:41:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _FLDEDT_HXX
#define _FLDEDT_HXX
#ifndef _BASEDLGS_HXX //autogen
#include <sfx2/basedlgs.hxx>
#endif

#ifndef _SV_BUTTON_HXX //autogen
#include <vcl/imagebtn.hxx>
#endif

class SwView;
class SwWrtShell;

/*--------------------------------------------------------------------
   Beschreibung:
 --------------------------------------------------------------------*/

class SwFldEditDlg : public SfxSingleTabDialog
{
    SwWrtShell* pSh;
    ImageButton aPrevBT;
    ImageButton aNextBT;
    PushButton  aAddressBT;

    DECL_LINK( AddressHdl, PushButton *pBt = 0 );
    DECL_LINK( NextPrevHdl, Button *pBt = 0 );

    void            Init();
    SfxTabPage*     CreatePage(USHORT nGroup);

public:

     SwFldEditDlg(SwView& rVw);
    ~SwFldEditDlg();

    DECL_LINK( OKHdl, Button * );

    virtual short   Execute();

    void            EnableInsert(BOOL bEnable);
    void            InsertHdl();
};

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.3.738); FILE MERGED 2008/04/01 15:59:11 thb 1.3.738.2: #i85898# Stripping all external header guards 2008/03/31 16:58:31 rt 1.3.738.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: fldedt.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _FLDEDT_HXX
#define _FLDEDT_HXX
#include <sfx2/basedlgs.hxx>
#include <vcl/imagebtn.hxx>

class SwView;
class SwWrtShell;

/*--------------------------------------------------------------------
   Beschreibung:
 --------------------------------------------------------------------*/

class SwFldEditDlg : public SfxSingleTabDialog
{
    SwWrtShell* pSh;
    ImageButton aPrevBT;
    ImageButton aNextBT;
    PushButton  aAddressBT;

    DECL_LINK( AddressHdl, PushButton *pBt = 0 );
    DECL_LINK( NextPrevHdl, Button *pBt = 0 );

    void            Init();
    SfxTabPage*     CreatePage(USHORT nGroup);

public:

     SwFldEditDlg(SwView& rVw);
    ~SwFldEditDlg();

    DECL_LINK( OKHdl, Button * );

    virtual short   Execute();

    void            EnableInsert(BOOL bEnable);
    void            InsertHdl();
};

#endif
<|endoftext|>


<commit_before>#include "PlayerControlsSystem.h"
#include <Updateable.h>
#include <ActionController.h>
#include <components/PlayerControls.h>
#include <components/PlayerStateComponent.h>
#include <Box2D/Common/b2Math.h>
#include <components/PhysicsComponent.h>
#include <unordered_map>
#include <functional>
#include <components/PlayerState.h>
#include <components/Texcoords.h>
#include <iostream>
#include <components/Sensors.h>
#include <components/SensorComponent.h>

class PlayerControlsSystem::PlayerControlsSystemImpl{

public:
	PlayerControlsSystemImpl() : m_moveLeft (PlayerControls::LEFT_KEY), m_moveRight (PlayerControls::RIGHT_KEY), m_jump (PlayerControls::JUMP_KEY),
								m_moveDown (PlayerControls::DOWN_KEY), m_moveLeftReleased(PlayerControls::LEFT_KEY,ActionType::Released), m_moveRightReleased(PlayerControls::RIGHT_KEY, ActionType::Released){
		 m_actionController[PlayerState::MOVE_LEFT] = m_moveLeft ;
	     m_actionController[PlayerState::MOVE_RIGHT] = m_moveRight ;
		 m_actionController[PlayerState::JUMP] = m_jump ;
		 m_actionController[PlayerState::MOVE_DOWN] = m_moveDown ;
//		 m_actionController[PlayerState::MOVE_LEFT_RELEASED] = m_moveLeftReleased ;
//		 m_actionController[PlayerState::MOVE_RIGHT_RELEASED] = m_moveRightReleased ;

		 m_actionController.addCallback(PlayerState::MOVE_LEFT, movePlayerLeft());
		 m_actionController.addCallback(PlayerState::MOVE_RIGHT,  movePlayerRight());
		 m_actionController.addCallback(PlayerState::JUMP,  playerJump());
		 m_actionController.addCallback(PlayerState::MOVE_LEFT_RELEASED,  movePlayerLeftReleased());
		 m_actionController.addCallback(PlayerState::MOVE_RIGHT_RELEASED,  movePlayerRightReleased());

		// m_actionController.addCallback(PlayerState::MOVE_DOWN,  movePlayerDown());
	}

	~PlayerControlsSystemImpl(){}

	Action m_moveLeft;
	Action m_moveLeftReleased;
	Action m_moveRightReleased;
	Action m_moveRight;
	Action m_jump;
	Action m_moveDown;

	sf::Clock m_clock;
	sf::Time m_leftPressed;
	sf::Time m_leftBoost;
	sf::Time m_rightBoost;
	sf::Time m_rightPressed;
	sf::Time m_lastJumpTime;

	float rightFrame = 1.0f/60.0f;
	float leftFrame = 1.0f/60.0f;
	float beginLeftBoostVal;
	float beginRightBoostVal;
	float m_switchDirectionBoost = 200.0f;
	bool m_leftBoostInAction;
	bool m_rightBoostInAction;

	bool m_isLeftWallJumpTriggered;
	bool m_isRightWallJumpTriggered;

	ActionController<PlayerState, TemplateHasher<PlayerState>, anax::Entity&> m_actionController;
	PlayerState m_currentPlayerState;

	b2Vec2 left;
	b2Vec2 right;
	b2Vec2 jump;
	b2Vec2 down;

	const float m_impulse = 40.0f;
	const float m_slowDownForce = 5.f;
	const float m_jumpImpulse = 160.0f;
	const float m_wallJumpForce = 300.0f;
	int movedLeft = 0;
	int movedRight = 0;
	int m_jumpedCount = 0;

	void update(sf::RenderWindow& window, float dt, std::vector<anax::Entity>& entities) {

		if(m_leftPressed.asMilliseconds() == 0){
			m_leftPressed = m_clock.getElapsedTime();
		}

		if(m_rightPressed.asMilliseconds() == 0){
			m_rightPressed = m_clock.getElapsedTime();
		}

	    if(movedLeft == 0 && movedRight ==0 ){
			for (auto entity : entities) {
				auto& physicsComponent = entity.getComponent<PhysicsComponent>();
				b2Body* body = physicsComponent.physicsBody;
				m_currentPlayerState = PlayerState::MOVE_LEFT_RELEASED;

				auto &sensorComps = entity.getComponent<Sensor>();
				auto sensor = sensorComps.sensors["FootSensor"];
					if(sensor.currentTotalContacts >= 1){
						body->SetLinearVelocity(b2Vec2(0, body->GetLinearVelocity().y));
					}
			}
	    }

	    movedLeft = 0;
	    movedRight = 0;
	    for(auto entity : entities){
	    		auto& playerStateComp = entity.getComponent<PlayerStateComponent>();
	   			m_actionController.triggerCallbacks(dt, entity);
	    		playerStateComp.playerState = m_currentPlayerState;
	    }

	    m_currentPlayerState = PlayerState::DEFAULT_STATE;
	}

	static float easeOutExpo(float currentTime,float beginingValue,float changeInValue, float duration){
		return (currentTime==duration) ? beginingValue+changeInValue : changeInValue * (- std::pow(6, -10 * currentTime/duration) + 1) + beginingValue;
	}

	std::function<void (float,  anax::Entity& entity)> movePlayerLeft() {
		return [this](float, anax::Entity& entity) {
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			auto & sensorComp = entity.getComponent<Sensor>().sensors["FootSensor"];

			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_LEFT;
			m_leftPressed = m_clock.getElapsedTime();
			float impulse = m_impulse;

			if(sensorComp.currentTotalContacts >= 1) {

				if(( m_leftPressed - m_rightPressed ).asMilliseconds() < 500 && movedRight== 0 && body->GetLinearVelocity().x > 0 && !m_leftBoostInAction) {
					m_leftBoostInAction = true;
					m_leftBoost = m_leftPressed;
					beginLeftBoostVal = body->GetLinearVelocity().x;
					leftFrame = 1.0f/60.0f;
				}
			}

			if(m_leftBoostInAction){
				leftFrame += 1.0f/60.0f;
				if(m_isLeftWallJumpTriggered){
					impulse = PlayerControlsSystemImpl::easeOutExpo(leftFrame,beginLeftBoostVal, -60  - beginLeftBoostVal ,2.0f);
				}else{
					impulse = PlayerControlsSystemImpl::easeOutExpo(leftFrame,beginLeftBoostVal, -m_switchDirectionBoost  - beginLeftBoostVal ,1.0f);
				}
				float elapsed = (m_leftPressed - m_leftBoost ).asMilliseconds();
				if(elapsed > 500.0f){
					m_leftBoostInAction = false;
					m_isLeftWallJumpTriggered = false;
				}
			}

			if(body->GetLinearVelocity().x > -40.0f ) {
				if(m_isLeftWallJumpTriggered && !m_leftBoostInAction && movedRight <= 0){
					body->ApplyForce( b2Vec2(-std::abs(impulse),-80), body->GetWorldCenter() , true);
					m_leftBoostInAction = true;
					m_leftBoost = m_leftPressed;
					leftFrame = 1.0f/60.0f;
					beginLeftBoostVal = body->GetLinearVelocity().x;
				}else{
					body->ApplyForce( b2Vec2(-std::abs(impulse),0.0f), body->GetWorldCenter() , true);
				}
			}
			movedLeft++;
		};
	}

	std::function<void (float, anax::Entity& entity)> movePlayerRight() {
		 return [this](float,  anax::Entity& entity){
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			auto & sensorComp = entity.getComponent<Sensor>().sensors["FootSensor"];

			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_RIGHT;
			float impulse = m_impulse;
			m_rightPressed = m_clock.getElapsedTime();

			if(sensorComp.currentTotalContacts >= 1) {

				if((m_rightPressed - m_leftPressed).asMilliseconds() < 500 && movedLeft== 0 && body->GetLinearVelocity().x < 0 && !m_rightBoostInAction) {
					std::cout << "in right" <<std::endl;
					m_rightBoostInAction = true;
					m_rightBoost = m_rightPressed;
					beginRightBoostVal= body->GetLinearVelocity().x;
					rightFrame = 1.0f/60.0f;
				}

			}

			if(m_rightBoostInAction){
				rightFrame += 1.0f/60.0f;
				if(m_isRightWallJumpTriggered){
					impulse = PlayerControlsSystemImpl::easeOutExpo(rightFrame,beginLeftBoostVal, 60  - beginRightBoostVal ,2.0f);
				}else{
					impulse = PlayerControlsSystemImpl::easeOutExpo(rightFrame,beginLeftBoostVal, m_switchDirectionBoost  - beginRightBoostVal ,1.0f);
				}
				float elapsed = (m_rightPressed - m_rightBoost ).asMilliseconds();
				if(elapsed > 1000.0f){
					m_rightBoostInAction = false;
					m_isRightWallJumpTriggered = false;
				}
			}

			if(body->GetLinearVelocity().x < 40.0f) {

				if(m_isRightWallJumpTriggered && !m_rightBoostInAction){
					body->ApplyForce( b2Vec2(std::abs(impulse),-80), body->GetWorldCenter() , true);
					m_rightBoostInAction = true;
					m_rightBoost = m_leftPressed;
					rightFrame = 1.0f/60.0f;
					beginLeftBoostVal = body->GetLinearVelocity().x;
				}else{
					body->ApplyForce( b2Vec2(std::abs(impulse),0.0f), body->GetWorldCenter() , true);
				}
			}
			movedRight++;
		};
	}

	std::function<void (float,  anax::Entity& entity)> movePlayerLeftReleased() {
		 return [this](float,  anax::Entity& entity){
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_LEFT_RELEASED;
			body->SetLinearVelocity(b2Vec2 (0,body->GetLinearVelocity().y));
		};
	}

	std::function<void (float,  anax::Entity& entity)> movePlayerRightReleased() {
		 return [this](float,  anax::Entity& entity){
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_RIGHT_RELEASED;
			body->SetLinearVelocity(b2Vec2 (0,body->GetLinearVelocity().y));
		};
	}

	std::function<void (float, anax::Entity& entity)> playerJump() {
		return [this](float,  anax::Entity& entity) {
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			auto & footSensor = entity.getComponent<Sensor>().sensors["FootSensor"];
			auto & rightSensor = entity.getComponent<Sensor>().sensors["RightSensor"];
			auto & leftSensor = entity.getComponent<Sensor>().sensors["LeftSensor"];

			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::JUMP;

			if(footSensor.currentTotalContacts >= 1){
				body->ApplyForce( b2Vec2(0.0f,-m_jumpImpulse), body->GetWorldCenter() , true);
			}else if(leftSensor.currentTotalContacts >= 1){
				body->ApplyForce( b2Vec2(m_wallJumpForce,-m_jumpImpulse*3), body->GetWorldCenter() , true);
				m_isLeftWallJumpTriggered = true;
			}else if(rightSensor.currentTotalContacts >= 1){
				body->ApplyForce( b2Vec2(-m_wallJumpForce,-m_jumpImpulse*3), body->GetWorldCenter() , true);
				m_isRightWallJumpTriggered = true;
			}
		};
	}

	std::function<void (float, anax::Entity& entity)> movePlayerDown() {
		return [this](float, anax::Entity& entity) {
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_DOWN;
			body->ApplyLinearImpulse( b2Vec2(0.0f,m_impulse) , body->GetWorldCenter() , true);
		};
	}
};

PlayerControlsSystem::PlayerControlsSystem() : Base(anax::ComponentFilter().requires<PlayerStateComponent, PhysicsComponent, Sensor>()), m_impl(new PlayerControlsSystemImpl()){
}

PlayerControlsSystem::~PlayerControlsSystem() {
}

void PlayerControlsSystem::update(sf::RenderWindow& window, float dt) {
    auto entities = getEntities();
    m_impl->update(window, dt, entities);
}

<commit_msg>slight refactor<commit_after>#include "PlayerControlsSystem.h"
#include <Updateable.h>
#include <ActionController.h>
#include <components/PlayerControls.h>
#include <components/PlayerStateComponent.h>
#include <Box2D/Common/b2Math.h>
#include <components/PhysicsComponent.h>
#include <unordered_map>
#include <functional>
#include <components/PlayerState.h>
#include <components/Texcoords.h>
#include <iostream>
#include <components/Sensors.h>
#include <components/SensorComponent.h>

class PlayerControlsSystem::PlayerControlsSystemImpl{

public:
	PlayerControlsSystemImpl() : m_moveLeft (PlayerControls::LEFT_KEY), m_moveRight (PlayerControls::RIGHT_KEY), m_jump (PlayerControls::JUMP_KEY),
								m_moveDown (PlayerControls::DOWN_KEY), m_moveLeftReleased(PlayerControls::LEFT_KEY,ActionType::Released), m_moveRightReleased(PlayerControls::RIGHT_KEY, ActionType::Released){
		 m_actionController[PlayerState::MOVE_LEFT] = m_moveLeft ;
	     m_actionController[PlayerState::MOVE_RIGHT] = m_moveRight ;
		 m_actionController[PlayerState::JUMP] = m_jump ;
		 m_actionController[PlayerState::MOVE_DOWN] = m_moveDown ;
//		 m_actionController[PlayerState::MOVE_LEFT_RELEASED] = m_moveLeftReleased ;
//		 m_actionController[PlayerState::MOVE_RIGHT_RELEASED] = m_moveRightReleased ;

		 m_actionController.addCallback(PlayerState::MOVE_LEFT, movePlayerLeft());
		 m_actionController.addCallback(PlayerState::MOVE_RIGHT,  movePlayerRight());
		 m_actionController.addCallback(PlayerState::JUMP,  playerJump());
		 m_actionController.addCallback(PlayerState::MOVE_LEFT_RELEASED,  movePlayerLeftReleased());
		 m_actionController.addCallback(PlayerState::MOVE_RIGHT_RELEASED,  movePlayerRightReleased());

		// m_actionController.addCallback(PlayerState::MOVE_DOWN,  movePlayerDown());
	}

	~PlayerControlsSystemImpl(){}

	Action m_moveLeft;
	Action m_moveLeftReleased;
	Action m_moveRightReleased;
	Action m_moveRight;
	Action m_jump;
	Action m_moveDown;

	sf::Clock m_clock;
	sf::Time m_changeInDirectionTime;
	sf::Time m_leftPressed;
	sf::Time m_rightPressed;
	sf::Time m_lastJumpTime;

	float frameIteration = 1.0f/60.0f;
	float beginBoostVal;
	float m_switchDirectionBoost = 200.0f;

	bool m_boostInAction;
	bool m_isLeftWallJumpTriggered;
	bool m_isRightWallJumpTriggered;

	ActionController<PlayerState, TemplateHasher<PlayerState>, anax::Entity&> m_actionController;
	PlayerState m_currentPlayerState;

	b2Vec2 left;
	b2Vec2 right;
	b2Vec2 jump;
	b2Vec2 down;

	const float m_impulse = 40.0f;
	const float m_slowDownForce = 5.f;
	const float m_jumpImpulse = 160.0f;
	const float m_wallJumpForce = 300.0f;
	int movedLeft = 0;
	int movedRight = 0;
	int m_jumpedCount = 0;

	void update(sf::RenderWindow& window, float dt, std::vector<anax::Entity>& entities) {

		if(m_leftPressed.asMilliseconds() == 0){
			m_leftPressed = m_clock.getElapsedTime();
		}

		if(m_rightPressed.asMilliseconds() == 0){
			m_rightPressed = m_clock.getElapsedTime();
		}

	    if(movedLeft == 0 && movedRight ==0 ){
			for (auto entity : entities) {
				auto& physicsComponent = entity.getComponent<PhysicsComponent>();
				b2Body* body = physicsComponent.physicsBody;
				m_currentPlayerState = PlayerState::MOVE_LEFT_RELEASED;

				auto &sensorComps = entity.getComponent<Sensor>();
				auto sensor = sensorComps.sensors["FootSensor"];
					if(sensor.currentTotalContacts >= 1){
						body->SetLinearVelocity(b2Vec2(0, body->GetLinearVelocity().y));
					}
			}
	    }

	    movedLeft = 0;
	    movedRight = 0;
	    for(auto entity : entities){
	    		auto& playerStateComp = entity.getComponent<PlayerStateComponent>();
	   			m_actionController.triggerCallbacks(dt, entity);
	    		playerStateComp.playerState = m_currentPlayerState;
	    }

	    m_currentPlayerState = PlayerState::DEFAULT_STATE;
	}

	static float easeOutExpo(float currentTime,float beginingValue,float changeInValue, float duration){
		return (currentTime==duration) ? beginingValue+changeInValue : changeInValue * (- std::pow(6, -10 * currentTime/duration) + 1) + beginingValue;
	}

	void setupChangeDirectionBoost(SensorComponent& footSensor,  float dtSinceChangeInDirection, int keyPressCount, b2Body* player){
		float xvelocity = player->GetLinearVelocity().x;
		if (footSensor.currentTotalContacts >= 1) {
			if (dtSinceChangeInDirection < 500 && movedRight == 0 && xvelocity > 0 && !m_boostInAction) {
				m_boostInAction = true;
				m_changeInDirectionTime = m_leftPressed;
				beginBoostVal = xvelocity;
				frameIteration = 1.0f / 60.0f;
			}
		}
	}

	void applyForce(b2Body* player,float impulse, int oppositeKeyPressedCount, bool isWalledJumped){
		float xVelocity = player->GetLinearVelocity().x ;
		b2Vec2 playerCenter = player->GetWorldCenter();
		if(xVelocity > -40.0f ) {
			if(isWalledJumped && !m_boostInAction && oppositeKeyPressedCount <= 0){
				player->ApplyForce( b2Vec2(impulse,-80), playerCenter , true);
				m_boostInAction = true;
				m_changeInDirectionTime = m_leftPressed;
				frameIteration = 1.0f/60.0f;
				beginBoostVal = xVelocity;
			}else{
				player->ApplyForce( b2Vec2(impulse,0.0f), playerCenter , true);
			}
		}
	}

	std::function<void (float,  anax::Entity& entity)> movePlayerLeft() {
		return [this](float, anax::Entity& entity) {
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			auto & sensorComp = entity.getComponent<Sensor>().sensors["FootSensor"];

			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_LEFT;
			m_leftPressed = m_clock.getElapsedTime();
			float impulse = m_impulse;

			setupChangeDirectionBoost(sensorComp, (m_leftPressed - m_rightPressed).asMilliseconds(), movedRight, body);

			if(m_boostInAction){
				frameIteration += 1.0f/60.0f;
				if(m_isLeftWallJumpTriggered){
					impulse = PlayerControlsSystemImpl::easeOutExpo(frameIteration,beginBoostVal, -60  - beginBoostVal ,2.0f);
				}else{
					impulse = PlayerControlsSystemImpl::easeOutExpo(frameIteration,beginBoostVal, -m_switchDirectionBoost  - beginBoostVal ,1.0f);
				}
				float elapsed = (m_leftPressed - m_changeInDirectionTime ).asMilliseconds();
				if(elapsed > 500.0f){
					m_boostInAction = false;
					m_isLeftWallJumpTriggered = false;
				}
			}

			applyForce(body, -std::abs(impulse), movedRight, m_isLeftWallJumpTriggered);
			movedLeft++;
		};
	}

	std::function<void (float, anax::Entity& entity)> movePlayerRight() {
		 return [this](float,  anax::Entity& entity){
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			auto & sensorComp = entity.getComponent<Sensor>().sensors["FootSensor"];

			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_RIGHT;
			float impulse = m_impulse;
			m_rightPressed = m_clock.getElapsedTime();

			if(sensorComp.currentTotalContacts >= 1) {

				if((m_rightPressed - m_leftPressed).asMilliseconds() < 500 && movedLeft== 0 && body->GetLinearVelocity().x < 0 && !m_boostInAction) {
					std::cout << "in right" <<std::endl;
					m_boostInAction = true;
					m_changeInDirectionTime = m_rightPressed;
					beginBoostVal= body->GetLinearVelocity().x;
					frameIteration = 1.0f/60.0f;
				}

			}

			if(m_boostInAction){
				frameIteration += 1.0f/60.0f;
				if(m_isRightWallJumpTriggered){
					impulse = PlayerControlsSystemImpl::easeOutExpo(frameIteration,beginBoostVal, 60  - beginBoostVal ,2.0f);
				}else{
					impulse = PlayerControlsSystemImpl::easeOutExpo(frameIteration,beginBoostVal, m_switchDirectionBoost  - beginBoostVal ,1.0f);
				}
				float elapsed = (m_rightPressed - m_changeInDirectionTime ).asMilliseconds();
				if(elapsed > 1000.0f){
					m_boostInAction = false;
					m_isRightWallJumpTriggered = false;
				}
			}

			if(body->GetLinearVelocity().x < 40.0f) {

				if(m_isRightWallJumpTriggered && !m_boostInAction){
					body->ApplyForce( b2Vec2(std::abs(impulse),-80), body->GetWorldCenter() , true);
					m_boostInAction = true;
					m_changeInDirectionTime = m_leftPressed;
					frameIteration = 1.0f/60.0f;
					beginBoostVal = body->GetLinearVelocity().x;
				}else{
					body->ApplyForce( b2Vec2(std::abs(impulse),0.0f), body->GetWorldCenter() , true);
				}
			}
			movedRight++;
		};
	}

	std::function<void (float,  anax::Entity& entity)> movePlayerLeftReleased() {
		 return [this](float,  anax::Entity& entity){
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_LEFT_RELEASED;
			body->SetLinearVelocity(b2Vec2 (0,body->GetLinearVelocity().y));
		};
	}

	std::function<void (float,  anax::Entity& entity)> movePlayerRightReleased() {
		 return [this](float,  anax::Entity& entity){
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_RIGHT_RELEASED;
			body->SetLinearVelocity(b2Vec2 (0,body->GetLinearVelocity().y));
		};
	}

	std::function<void (float, anax::Entity& entity)> playerJump() {
		return [this](float,  anax::Entity& entity) {
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			auto & footSensor = entity.getComponent<Sensor>().sensors["FootSensor"];
			auto & rightSensor = entity.getComponent<Sensor>().sensors["RightSensor"];
			auto & leftSensor = entity.getComponent<Sensor>().sensors["LeftSensor"];

			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::JUMP;

			if(footSensor.currentTotalContacts >= 1){
				body->ApplyForce( b2Vec2(0.0f,-m_jumpImpulse), body->GetWorldCenter() , true);
			}else if(leftSensor.currentTotalContacts >= 1){
				body->ApplyForce( b2Vec2(m_wallJumpForce,-m_jumpImpulse*3), body->GetWorldCenter() , true);
				m_isLeftWallJumpTriggered = true;
			}else if(rightSensor.currentTotalContacts >= 1){
				body->ApplyForce( b2Vec2(-m_wallJumpForce,-m_jumpImpulse*3), body->GetWorldCenter() , true);
				m_isRightWallJumpTriggered = true;
			}
		};
	}

	std::function<void (float, anax::Entity& entity)> movePlayerDown() {
		return [this](float, anax::Entity& entity) {
			auto& physicsComponent = entity.getComponent<PhysicsComponent>();
			b2Body* body = physicsComponent.physicsBody;
			m_currentPlayerState = PlayerState::MOVE_DOWN;
			body->ApplyLinearImpulse( b2Vec2(0.0f,m_impulse) , body->GetWorldCenter() , true);
		};
	}
};

PlayerControlsSystem::PlayerControlsSystem() : Base(anax::ComponentFilter().requires<PlayerStateComponent, PhysicsComponent, Sensor>()), m_impl(new PlayerControlsSystemImpl()){
}

PlayerControlsSystem::~PlayerControlsSystem() {
}

void PlayerControlsSystem::update(sf::RenderWindow& window, float dt) {
    auto entities = getEntities();
    m_impl->update(window, dt, entities);
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: fldmgr.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: rt $ $Date: 2004-08-23 10:51:41 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _FLDMGR_HXX
#define _FLDMGR_HXX

#ifndef _SVSTDARR_HXX
#define _SVSTDARR_STRINGSDTOR
#include <svtools/svstdarr.hxx>
#endif

#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif

#ifndef INCLUDED_SWDLLAPI_H
#include "swdllapi.h"
#endif

#ifndef _SWTYPES_HXX
#include "swtypes.hxx"
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_H_
#include <com/sun/star/uno/Any.h>
#endif

namespace com{namespace sun{namespace star{
    namespace container{
        class XNameAccess;
    }
    namespace text{
        class XNumberingTypeInfo;
    }
}}}

class SwWrtShell;
class SwField;
class SwFieldType;
class SwFmtRefMark;
class SbModule;
class SvxMacroItem;
class ListBox;
class SvNumberFormatter;
class Window;
/*--------------------------------------------------------------------
    Beschreibung: Die Gruppen von Feldern
 --------------------------------------------------------------------*/

enum SwFldGroups
{
    GRP_DOC,
    GRP_FKT,
    GRP_REF,
    GRP_REG,
    GRP_DB,
    GRP_VAR
};

struct SwFldGroupRgn
{
    USHORT nStart;
    USHORT nEnd;
};

/*--------------------------------------------------------------------
    Beschreibung:  Der FeldManager handelt das Einfuegen von Felder
                    ueber Command-Strings
 --------------------------------------------------------------------*/
struct SwInsertFld_Data
{
    USHORT nTypeId;
    USHORT nSubType;
    const String sPar1;
    const String sPar2;
    ULONG nFormatId;
    SwWrtShell* pSh;
    sal_Unicode cSeparator;
    BOOL bIsAutomaticLanguage;
    ::com::sun::star::uno::Any aDBDataSource;
    ::com::sun::star::uno::Any aDBConnection;
    ::com::sun::star::uno::Any aDBColumn;
    Window* pParent; // parent dialog used for SwWrtShell::StartInputFldDlg()

    SwInsertFld_Data(USHORT nType, USHORT nSub, const String& rPar1, const String& rPar2,
                    ULONG nFmtId, SwWrtShell* pShell = NULL, sal_Unicode cSep = ' ', BOOL bIsAutoLanguage = TRUE) :
        nTypeId(nType),
        nSubType(nSub),
        sPar1(rPar1),
        sPar2(rPar2),
        nFormatId(nFmtId),
        pSh(pShell),
        cSeparator(cSep),
        bIsAutomaticLanguage(bIsAutoLanguage),
        pParent(0) {}

    SwInsertFld_Data() :
        pSh(0),
        cSeparator(' '),
        bIsAutomaticLanguage(TRUE){}

};

class SW_DLLPUBLIC SwFldMgr
{
private:
    SwField*            pCurFld;
    SbModule*           pModule;
    const SvxMacroItem* pMacroItem;
    SwWrtShell*         pWrtShell; // darf auch NULL sein!
    String          aCurPar1;
    String          aCurPar2;
    String          sCurFrame;

    String          sMacroPath;
    String          sMacroName;

    ULONG           nCurFmt;
    BOOL            bEvalExp;

    SW_DLLPRIVATE USHORT            GetCurrLanguage() const;

    com::sun::star::uno::Reference<com::sun::star::container::XNameAccess> xDBContext;
    com::sun::star::uno::Reference<com::sun::star::text::XNumberingTypeInfo> xNumberingInfo;
    SW_DLLPRIVATE com::sun::star::uno::Reference<com::sun::star::text::XNumberingTypeInfo> GetNumberingInfo()const;

public:
    SwFldMgr(SwWrtShell* pSh = 0);
    ~SwFldMgr();

    // Feld einfuegen ueber TypeId (TYP_ ...)
    BOOL            InsertFld(  const SwInsertFld_Data& rData );

    // Direkt das aktuelle Feld aendern
    void            UpdateCurFld(ULONG nFormat,
                                 const String& rPar1,
                                 const String& rPar2,
                                 SwField * _pField = 0); // #111840#

    inline const String& GetCurFldPar1() const;
    inline const String& GetCurFldPar2() const;
    inline const ULONG   GetCurFldFmt() const;

    // Ein Feld ermitteln
    SwField*        GetCurFld();

    void            InsertFldType(SwFieldType& rType);

    BOOL            ChooseMacro(const String &rSelMacro = aEmptyStr);
    void            SetMacroPath(const String& rPath);
    inline const String& GetMacroPath() const         { return (sMacroPath); }
    inline const String& GetMacroName() const         { return (sMacroName); }
    inline void     SetMacroModule(SbModule* pMod)    { pModule = pMod; }

    // Vorheriger Naechster gleichen Typ
    BOOL GoNextPrev( BOOL bNext = TRUE, SwFieldType* pTyp = 0 );
    BOOL GoNext( SwFieldType* pTyp = 0 )    { return GoNextPrev( TRUE, pTyp ); }
    BOOL GoPrev( SwFieldType* pTyp = 0 )    { return GoNextPrev( FALSE, pTyp ); }

    // Erfragen von Werten aus Datenbankfeldern (BASIC )
//  String          GetDataBaseFieldValue(const String &rDBName, const String &rFieldName, SwWrtShell* pSh);
    BOOL            IsDBNumeric(const String& rDBName, const String& rTblQryName,
                                        BOOL bIsTable, const String& rFldName);

    // RefMark mit Namen organisieren
    BOOL            CanInsertRefMark( const String& rStr );

    // Zugriff ueber ResId auf Feldtypen
    USHORT          GetFldTypeCount(USHORT nResId = USHRT_MAX) const;
    SwFieldType*    GetFldType(USHORT nResId, USHORT nId = 0) const;
    SwFieldType*    GetFldType(USHORT nResId, const String& rName) const;

    void            RemoveFldType(USHORT nResId, const String& rName);

    // Zugriff ueber TypeId aus dem Dialog
    // Ids fuer einen Bereich von Feldern
    const SwFldGroupRgn& GetGroupRange(BOOL bHtmlMode, USHORT nGrpId) const;
    USHORT          GetGroup(BOOL bHtmlMode, USHORT nTypeId, USHORT nSubType = 0) const;

    // TypeId des aktuellen Feldes
    USHORT          GetCurTypeId() const;

    // TypeId fuer einen konkrete Pos in der Liste
    static USHORT   GetTypeId(USHORT nPos);
    // Name des Typen in der Liste der Felder
    static const String&  GetTypeStr(USHORT nPos);

    // Pos in der Liste der Felder
    static USHORT   GetPos(USHORT nTypeId);

    // Untertypen zu einem Typ
    BOOL            GetSubTypes(USHORT nId, SvStringsDtor& rToFill);

    // Formate zu einem Typ
    USHORT          GetFormatCount(USHORT nTypeId, BOOL bIsText, BOOL bHtmlMode = FALSE) const;
    String          GetFormatStr(USHORT nTypeId, ULONG nFormatId) const;
    USHORT          GetFormatId(USHORT nTypeId, ULONG nFormatId) const;
    ULONG           GetDefaultFormat(USHORT nTypeId, BOOL bIsText, SvNumberFormatter* pFormatter, double* pVal = 0L);

    // Evaluierung der ExpressionFelder ausschalten fuer das Einfuegen
    // vieler Expressionfelder (siehe Etiketten)
    //
    inline void     SetEvalExpFlds(BOOL bEval);
    void            EvalExpFlds(SwWrtShell* pSh = NULL);
};

inline void SwFldMgr::SetEvalExpFlds(BOOL bEval)
    { bEvalExp = bEval; }

inline const String& SwFldMgr::GetCurFldPar1() const
    { return aCurPar1; }

inline const String& SwFldMgr::GetCurFldPar2() const
    { return aCurPar2; }

inline const ULONG   SwFldMgr::GetCurFldFmt() const
    { return nCurFmt; }

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.12.596); FILE MERGED 2005/09/05 13:45:11 rt 1.12.596.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fldmgr.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:13:40 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _FLDMGR_HXX
#define _FLDMGR_HXX

#ifndef _SVSTDARR_HXX
#define _SVSTDARR_STRINGSDTOR
#include <svtools/svstdarr.hxx>
#endif

#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif

#ifndef INCLUDED_SWDLLAPI_H
#include "swdllapi.h"
#endif

#ifndef _SWTYPES_HXX
#include "swtypes.hxx"
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_H_
#include <com/sun/star/uno/Any.h>
#endif

namespace com{namespace sun{namespace star{
    namespace container{
        class XNameAccess;
    }
    namespace text{
        class XNumberingTypeInfo;
    }
}}}

class SwWrtShell;
class SwField;
class SwFieldType;
class SwFmtRefMark;
class SbModule;
class SvxMacroItem;
class ListBox;
class SvNumberFormatter;
class Window;
/*--------------------------------------------------------------------
    Beschreibung: Die Gruppen von Feldern
 --------------------------------------------------------------------*/

enum SwFldGroups
{
    GRP_DOC,
    GRP_FKT,
    GRP_REF,
    GRP_REG,
    GRP_DB,
    GRP_VAR
};

struct SwFldGroupRgn
{
    USHORT nStart;
    USHORT nEnd;
};

/*--------------------------------------------------------------------
    Beschreibung:  Der FeldManager handelt das Einfuegen von Felder
                    ueber Command-Strings
 --------------------------------------------------------------------*/
struct SwInsertFld_Data
{
    USHORT nTypeId;
    USHORT nSubType;
    const String sPar1;
    const String sPar2;
    ULONG nFormatId;
    SwWrtShell* pSh;
    sal_Unicode cSeparator;
    BOOL bIsAutomaticLanguage;
    ::com::sun::star::uno::Any aDBDataSource;
    ::com::sun::star::uno::Any aDBConnection;
    ::com::sun::star::uno::Any aDBColumn;
    Window* pParent; // parent dialog used for SwWrtShell::StartInputFldDlg()

    SwInsertFld_Data(USHORT nType, USHORT nSub, const String& rPar1, const String& rPar2,
                    ULONG nFmtId, SwWrtShell* pShell = NULL, sal_Unicode cSep = ' ', BOOL bIsAutoLanguage = TRUE) :
        nTypeId(nType),
        nSubType(nSub),
        sPar1(rPar1),
        sPar2(rPar2),
        nFormatId(nFmtId),
        pSh(pShell),
        cSeparator(cSep),
        bIsAutomaticLanguage(bIsAutoLanguage),
        pParent(0) {}

    SwInsertFld_Data() :
        pSh(0),
        cSeparator(' '),
        bIsAutomaticLanguage(TRUE){}

};

class SW_DLLPUBLIC SwFldMgr
{
private:
    SwField*            pCurFld;
    SbModule*           pModule;
    const SvxMacroItem* pMacroItem;
    SwWrtShell*         pWrtShell; // darf auch NULL sein!
    String          aCurPar1;
    String          aCurPar2;
    String          sCurFrame;

    String          sMacroPath;
    String          sMacroName;

    ULONG           nCurFmt;
    BOOL            bEvalExp;

    SW_DLLPRIVATE USHORT            GetCurrLanguage() const;

    com::sun::star::uno::Reference<com::sun::star::container::XNameAccess> xDBContext;
    com::sun::star::uno::Reference<com::sun::star::text::XNumberingTypeInfo> xNumberingInfo;
    SW_DLLPRIVATE com::sun::star::uno::Reference<com::sun::star::text::XNumberingTypeInfo> GetNumberingInfo()const;

public:
    SwFldMgr(SwWrtShell* pSh = 0);
    ~SwFldMgr();

    // Feld einfuegen ueber TypeId (TYP_ ...)
    BOOL            InsertFld(  const SwInsertFld_Data& rData );

    // Direkt das aktuelle Feld aendern
    void            UpdateCurFld(ULONG nFormat,
                                 const String& rPar1,
                                 const String& rPar2,
                                 SwField * _pField = 0); // #111840#

    inline const String& GetCurFldPar1() const;
    inline const String& GetCurFldPar2() const;
    inline const ULONG   GetCurFldFmt() const;

    // Ein Feld ermitteln
    SwField*        GetCurFld();

    void            InsertFldType(SwFieldType& rType);

    BOOL            ChooseMacro(const String &rSelMacro = aEmptyStr);
    void            SetMacroPath(const String& rPath);
    inline const String& GetMacroPath() const         { return (sMacroPath); }
    inline const String& GetMacroName() const         { return (sMacroName); }
    inline void     SetMacroModule(SbModule* pMod)    { pModule = pMod; }

    // Vorheriger Naechster gleichen Typ
    BOOL GoNextPrev( BOOL bNext = TRUE, SwFieldType* pTyp = 0 );
    BOOL GoNext( SwFieldType* pTyp = 0 )    { return GoNextPrev( TRUE, pTyp ); }
    BOOL GoPrev( SwFieldType* pTyp = 0 )    { return GoNextPrev( FALSE, pTyp ); }

    // Erfragen von Werten aus Datenbankfeldern (BASIC )
//  String          GetDataBaseFieldValue(const String &rDBName, const String &rFieldName, SwWrtShell* pSh);
    BOOL            IsDBNumeric(const String& rDBName, const String& rTblQryName,
                                        BOOL bIsTable, const String& rFldName);

    // RefMark mit Namen organisieren
    BOOL            CanInsertRefMark( const String& rStr );

    // Zugriff ueber ResId auf Feldtypen
    USHORT          GetFldTypeCount(USHORT nResId = USHRT_MAX) const;
    SwFieldType*    GetFldType(USHORT nResId, USHORT nId = 0) const;
    SwFieldType*    GetFldType(USHORT nResId, const String& rName) const;

    void            RemoveFldType(USHORT nResId, const String& rName);

    // Zugriff ueber TypeId aus dem Dialog
    // Ids fuer einen Bereich von Feldern
    const SwFldGroupRgn& GetGroupRange(BOOL bHtmlMode, USHORT nGrpId) const;
    USHORT          GetGroup(BOOL bHtmlMode, USHORT nTypeId, USHORT nSubType = 0) const;

    // TypeId des aktuellen Feldes
    USHORT          GetCurTypeId() const;

    // TypeId fuer einen konkrete Pos in der Liste
    static USHORT   GetTypeId(USHORT nPos);
    // Name des Typen in der Liste der Felder
    static const String&  GetTypeStr(USHORT nPos);

    // Pos in der Liste der Felder
    static USHORT   GetPos(USHORT nTypeId);

    // Untertypen zu einem Typ
    BOOL            GetSubTypes(USHORT nId, SvStringsDtor& rToFill);

    // Formate zu einem Typ
    USHORT          GetFormatCount(USHORT nTypeId, BOOL bIsText, BOOL bHtmlMode = FALSE) const;
    String          GetFormatStr(USHORT nTypeId, ULONG nFormatId) const;
    USHORT          GetFormatId(USHORT nTypeId, ULONG nFormatId) const;
    ULONG           GetDefaultFormat(USHORT nTypeId, BOOL bIsText, SvNumberFormatter* pFormatter, double* pVal = 0L);

    // Evaluierung der ExpressionFelder ausschalten fuer das Einfuegen
    // vieler Expressionfelder (siehe Etiketten)
    //
    inline void     SetEvalExpFlds(BOOL bEval);
    void            EvalExpFlds(SwWrtShell* pSh = NULL);
};

inline void SwFldMgr::SetEvalExpFlds(BOOL bEval)
    { bEvalExp = bEval; }

inline const String& SwFldMgr::GetCurFldPar1() const
    { return aCurPar1; }

inline const String& SwFldMgr::GetCurFldPar2() const
    { return aCurPar2; }

inline const ULONG   SwFldMgr::GetCurFldFmt() const
    { return nCurFmt; }

#endif

<|endoftext|>