summaryrefslogtreecommitdiff
path: root/src/hooks.cc
blob: 4fcc39d3ff02c73b2a314432aeef54806ebb83a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 * Copyright (c) 2001 James E. Wilson, Robert A. Koeneke, DarkGod
 *
 * This software may be copied and distributed for educational, research, and
 * not for profit purposes provided that this copyright and statement are
 * included in all such copies.
 */
#include "hooks.hpp"

#include <algorithm>
#include <assert.h>
#include <unordered_map>
#include <vector>

/******** Hooks stuff *********/

struct hook_data
{
private:
	hook_func_t m_hook_func;
	void *m_hook_data;
public:
	hook_data(hook_func_t hook_func, void *hook_data)
		: m_hook_func(hook_func)
		, m_hook_data(hook_data) {
	}

	hook_data() = delete;

	/**
	 * Check if the given hook points to the given function.
	 */
	bool is(hook_func_t hook_func) const {
		return m_hook_func == hook_func;
	}

	/**
	 * Invoke the hook with the given input and output pointers.
	 */
	bool_ invoke(void *in, void *out) const {
		return m_hook_func(m_hook_data, in, out);
	}
};

std::unordered_map<size_t, std::vector<hook_data>> &hooks_instance()
{
	static auto instance = new std::unordered_map<size_t, std::vector<hook_data>>();
	return *instance;
}


int process_hooks_restart = FALSE;

static std::vector<hook_data>::iterator find_hook(std::vector<hook_data> &hooks, hook_func_t hook_func)
{
	return std::find_if(hooks.begin(),
			    hooks.end(),
			    [&](const hook_data &hook_data) {
				    return hook_data.is(hook_func);
			    });
}

void add_hook_new(int h_idx, hook_func_t hook_func, cptr name, void *data)
{
	auto &hooks = hooks_instance()[h_idx];
	// Only insert if not already present.
	if (find_hook(hooks, hook_func) == hooks.end()) {
		hooks.emplace_back(hook_func, data);
	}
}

void del_hook_new(int h_idx, hook_func_t hook_func)
{
	auto &hooks = hooks_instance()[h_idx];

	/* Find it */
	auto found_it = find_hook(hooks, hook_func);
	if (found_it != hooks.end())
	{
		hooks.erase(found_it);
	}
}

bool_ process_hooks_new(int h_idx, void *in, void *out)
{
	auto const &hooks = hooks_instance()[h_idx];

	auto hooks_it = hooks.begin();
	while (hooks_it != hooks.end())
	{
		auto &hook_data = *hooks_it;

		/* Invoke hook function; stop processing if the hook
		   returns TRUE */
		if (hook_data.invoke(in, out))
		{
			return TRUE;
		}

		/* Should we restart processing at the beginning? */
		if (process_hooks_restart)
		{
			hooks_it = hooks.begin();
			process_hooks_restart = FALSE;
		}
		else
		{
			hooks_it++;
		}
	}

	return FALSE;
}