1 /*
2 * disco.c
3 * vim: expandtab:ts=4:sts=4:sw=4
4 *
5 * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
6 *
7 * This file is part of Profanity.
8 *
9 * Profanity is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Profanity is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Profanity. If not, see <https://www.gnu.org/licenses/>.
21 *
22 * In addition, as a special exception, the copyright holders give permission to
23 * link the code of portions of this program with the OpenSSL library under
24 * certain conditions as described in each individual source file, and
25 * distribute linked combinations including the two.
26 *
27 * You must obey the GNU General Public License in all respects for all of the
28 * code used other than OpenSSL. If you modify file(s) with this exception, you
29 * may extend this exception to your version of the file(s), but you are not
30 * obligated to do so. If you do not wish to do so, delete this exception
31 * statement from your version. If you delete this exception statement from all
32 * source files in the program, then also delete it here.
33 *
34 */
35
36 #include "config.h"
37
38 #include <string.h>
39 #include <stdlib.h>
40
41 #include <glib.h>
42
43 // features to reference count map
44 static GHashTable* features = NULL;
45
46 // plugin to feature map
47 static GHashTable* plugin_to_features = NULL;
48
49 static void
_free_features(GHashTable * features)50 _free_features(GHashTable* features)
51 {
52 g_hash_table_destroy(features);
53 }
54
55 void
disco_add_feature(const char * plugin_name,char * feature)56 disco_add_feature(const char* plugin_name, char* feature)
57 {
58 if (feature == NULL || plugin_name == NULL) {
59 return;
60 }
61
62 if (!features) {
63 features = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
64 }
65 if (!plugin_to_features) {
66 plugin_to_features = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_features);
67 }
68
69 GHashTable* plugin_features = g_hash_table_lookup(plugin_to_features, plugin_name);
70 gboolean added = FALSE;
71 if (plugin_features == NULL) {
72 plugin_features = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
73 g_hash_table_add(plugin_features, strdup(feature));
74 g_hash_table_insert(plugin_to_features, strdup(plugin_name), plugin_features);
75 added = TRUE;
76 } else if (!g_hash_table_contains(plugin_features, feature)) {
77 g_hash_table_add(plugin_features, strdup(feature));
78 added = TRUE;
79 }
80
81 if (added == FALSE) {
82 return;
83 }
84
85 if (!g_hash_table_contains(features, feature)) {
86 g_hash_table_insert(features, strdup(feature), GINT_TO_POINTER(1));
87 } else {
88 void* refcountp = g_hash_table_lookup(features, feature);
89 int refcount = GPOINTER_TO_INT(refcountp);
90 refcount++;
91 g_hash_table_replace(features, strdup(feature), GINT_TO_POINTER(refcount));
92 }
93 }
94
95 void
disco_remove_features(const char * plugin_name)96 disco_remove_features(const char* plugin_name)
97 {
98 if (!features) {
99 return;
100 }
101 if (!plugin_to_features) {
102 return;
103 }
104
105 GHashTable* plugin_features_set = g_hash_table_lookup(plugin_to_features, plugin_name);
106 if (!plugin_features_set) {
107 return;
108 }
109
110 GList* plugin_feature_list = g_hash_table_get_keys(plugin_features_set);
111 GList* curr = plugin_feature_list;
112 while (curr) {
113 char* feature = curr->data;
114 if (g_hash_table_contains(features, feature)) {
115 void* refcountp = g_hash_table_lookup(features, feature);
116 int refcount = GPOINTER_TO_INT(refcountp);
117 if (refcount == 1) {
118 g_hash_table_remove(features, feature);
119 } else {
120 refcount--;
121 g_hash_table_replace(features, strdup(feature), GINT_TO_POINTER(refcount));
122 }
123 }
124
125 curr = g_list_next(curr);
126 }
127 g_list_free(plugin_feature_list);
128 }
129
130 GList*
disco_get_features(void)131 disco_get_features(void)
132 {
133 if (features == NULL) {
134 return NULL;
135 }
136
137 return g_hash_table_get_keys(features);
138 }
139
140 void
disco_close(void)141 disco_close(void)
142 {
143 if (features) {
144 g_hash_table_destroy(features);
145 features = NULL;
146 }
147
148 if (plugin_to_features) {
149 g_hash_table_destroy(plugin_to_features);
150 plugin_to_features = NULL;
151 }
152 }
153