]> jfr.im git - solanum.git/blobdiff - src/capability.c
update NEWS
[solanum.git] / src / capability.c
index c61c006c6b76ed2303060e749c7bda21e41d44aa..daf72657bdb98e8556d04784f0c4af27fbc38390 100644 (file)
 #include "stdinc.h"
 #include "capability.h"
 #include "irc_dictionary.h"
+#include "s_assert.h"
+
+static rb_dlink_list capability_indexes = { NULL, NULL, 0 };
 
 struct CapabilityIndex {
+       char *name;
        struct Dictionary *cap_dict;
        unsigned int highest_bit;
+       rb_dlink_node node;
 };
 
+#define CAP_ORPHANED   0x1
+#define CAP_REQUIRED   0x2
+
 struct CapabilityEntry {
-       unsigned int orphaned;
+       char *cap;
        unsigned int value;
+       unsigned int flags;
 };
 
 unsigned int
-capability_get(struct CapabilityIndex *index, const char *cap)
+capability_get(struct CapabilityIndex *idx, const char *cap)
 {
        struct CapabilityEntry *entry;
 
-       s_assert(index != NULL);
+       s_assert(idx != NULL);
+       if (cap == NULL)
+               return 0;
 
-       entry = irc_dictionary_retrieve(index->cap_dict, cap);
-       if (entry != NULL && !entry->orphaned)
-               return entry->value;
+       entry = irc_dictionary_retrieve(idx->cap_dict, cap);
+       if (entry != NULL && !(entry->flags & CAP_ORPHANED))
+               return (1 << entry->value);
 
-       return 0xFFFFFFFF;
+       return 0;
 }
 
 unsigned int
-capability_put(struct CapabilityIndex *index, const char *cap)
+capability_put(struct CapabilityIndex *idx, const char *cap)
 {
        struct CapabilityEntry *entry;
 
-       s_assert(index != NULL);
+       s_assert(idx != NULL);
+       if (!idx->highest_bit)
+               return 0xFFFFFFFF;
 
-       if ((entry = irc_dictionary_retrieve(index->cap_dict, cap)) != NULL)
+       if ((entry = irc_dictionary_retrieve(idx->cap_dict, cap)) != NULL)
        {
-               entry->orphaned = 0;
-               return entry->value;
+               entry->flags &= ~CAP_ORPHANED;
+               return (1 << entry->value);
        }
 
        entry = rb_malloc(sizeof(struct CapabilityEntry));
-       entry->orphaned = 0;
-       entry->value = index->highest_bit;
+       entry->cap = rb_strdup(cap);
+       entry->flags = 0;
+       entry->value = idx->highest_bit;
 
-       irc_dictionary_add(index->cap_dict, cap, entry);
+       irc_dictionary_add(idx->cap_dict, entry->cap, entry);
 
-       index->highest_bit <<= 1;
+       idx->highest_bit++;
+       if (idx->highest_bit % (sizeof(unsigned int) * 8) == 0)
+               idx->highest_bit = 0;
+
+       return (1 << entry->value);
+}
 
-       /* hmm... not sure what to do here, so i guess we will abort for now... --nenolod */
-       if (index->highest_bit == 0)
-               abort();
+unsigned int
+capability_put_anonymous(struct CapabilityIndex *idx)
+{
+       unsigned int value;
 
-       return entry->value;
+       s_assert(idx != NULL);
+       if (!idx->highest_bit)
+               return 0xFFFFFFFF;
+       value = 1 << idx->highest_bit;
+       idx->highest_bit++;
+       if (idx->highest_bit % (sizeof(unsigned int) * 8) == 0)
+               idx->highest_bit = 0;
+       return value;
 }
 
 void
-capability_orphan(struct CapabilityIndex *index, const char *cap)
+capability_orphan(struct CapabilityIndex *idx, const char *cap)
 {
        struct CapabilityEntry *entry;
 
-       s_assert(index != NULL);
+       s_assert(idx != NULL);
 
-       entry = irc_dictionary_retrieve(index->cap_dict, cap);
+       entry = irc_dictionary_retrieve(idx->cap_dict, cap);
        if (entry != NULL)
-               entry->orphaned = 1;
+       {
+               entry->flags &= ~CAP_REQUIRED;
+               entry->flags |= CAP_ORPHANED;
+       }
+}
+
+void
+capability_require(struct CapabilityIndex *idx, const char *cap)
+{
+       struct CapabilityEntry *entry;
+
+       s_assert(idx != NULL);
+
+       entry = irc_dictionary_retrieve(idx->cap_dict, cap);
+       if (entry != NULL)
+               entry->flags |= CAP_REQUIRED;
 }
 
 static void
@@ -95,28 +137,33 @@ capability_destroy(struct DictionaryElement *delem, void *privdata)
 }
 
 struct CapabilityIndex *
-capability_index_create(void)
+capability_index_create(const char *name)
 {
-       struct CapabilityIndex *index;
+       struct CapabilityIndex *idx;
+
+       idx = rb_malloc(sizeof(struct CapabilityIndex));
+       idx->name = rb_strdup(name);
+       idx->cap_dict = irc_dictionary_create(strcasecmp);
+       idx->highest_bit = 1;
 
-       index = rb_malloc(sizeof(struct CapabilityIndex));
-       index->cap_dict = irc_dictionary_create(strcasecmp);
-       index->highest_bit = 1;
+       rb_dlinkAdd(idx, &idx->node, &capability_indexes);
 
-       return index;
+       return idx;
 }
 
 void
-capability_index_destroy(struct CapabilityIndex *index)
+capability_index_destroy(struct CapabilityIndex *idx)
 {
-       s_assert(index != NULL);
+       s_assert(idx != NULL);
 
-       irc_dictionary_destroy(index->cap_dict, capability_destroy, NULL);
-       rb_free(index);
+       rb_dlinkDelete(&idx->node, &capability_indexes);
+
+       irc_dictionary_destroy(idx->cap_dict, capability_destroy, NULL);
+       rb_free(idx);
 }
 
 const char *
-capability_index_list(struct CapabilityIndex *index, unsigned int cap_mask)
+capability_index_list(struct CapabilityIndex *idx, unsigned int cap_mask)
 {
        struct DictionaryIter iter;
        struct CapabilityEntry *entry;
@@ -124,15 +171,15 @@ capability_index_list(struct CapabilityIndex *index, unsigned int cap_mask)
        char *t = buf;
        int tl;
 
-       s_assert(index != NULL);
+       s_assert(idx != NULL);
 
        *t = '\0';
 
-       DICTIONARY_FOREACH(entry, &iter, index->cap_dict)
+       DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
        {
-               if (entry->value & cap_mask)
+               if ((1 << entry->value) & cap_mask)
                {
-                       tl = rb_sprintf(t, "%s ", iter.cur->key);
+                       tl = rb_sprintf(t, "%s ", entry->cap);
                        t += tl;
                }
        }
@@ -142,3 +189,69 @@ capability_index_list(struct CapabilityIndex *index, unsigned int cap_mask)
 
        return buf;
 }
+
+unsigned int
+capability_index_mask(struct CapabilityIndex *idx)
+{
+       struct DictionaryIter iter;
+       struct CapabilityEntry *entry;
+       unsigned int mask = 0;
+
+       s_assert(idx != NULL);
+
+       DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
+       {
+               if (!(entry->flags & CAP_ORPHANED))
+                       mask |= (1 << entry->value);
+       }
+
+       return mask;
+}
+
+unsigned int
+capability_index_get_required(struct CapabilityIndex *idx)
+{
+       struct DictionaryIter iter;
+       struct CapabilityEntry *entry;
+       unsigned int mask = 0;
+
+       s_assert(idx != NULL);
+
+       DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
+       {
+               if (!(entry->flags & CAP_ORPHANED) && (entry->flags & CAP_REQUIRED))
+                       mask |= (1 << entry->value);
+       }
+
+       return mask;
+}
+
+void
+capability_index_stats(void (*cb)(const char *line, void *privdata), void *privdata)
+{
+       rb_dlink_node *node;
+       char buf[BUFSIZE];
+
+       RB_DLINK_FOREACH(node, capability_indexes.head)
+       {
+               struct CapabilityIndex *idx = node->data;
+               struct DictionaryIter iter;
+               struct CapabilityEntry *entry;
+
+               rb_snprintf(buf, sizeof buf, "'%s': allocated bits - %d", idx->name, (idx->highest_bit - 1));
+               cb(buf, privdata);
+
+               DICTIONARY_FOREACH(entry, &iter, idx->cap_dict)
+               {
+                       rb_snprintf(buf, sizeof buf, "bit %d: '%s'", entry->value, entry->cap);
+                       cb(buf, privdata);
+               }
+
+               rb_snprintf(buf, sizeof buf, "'%s': remaining bits - %u", idx->name,
+                           (unsigned int)((sizeof(unsigned int) * 8) - (idx->highest_bit - 1)));
+               cb(buf, privdata);
+       }
+
+       rb_snprintf(buf, sizeof buf, "%ld capability indexes", rb_dlink_list_length(&capability_indexes));
+       cb(buf, privdata);
+}