Revision: 1885
          
http://undernet-ircu.svn.sourceforge.net/undernet-ircu/?rev=1885&view=rev
Author:   klmitch
Date:     2008-10-04 03:29:22 +0000 (Sat, 04 Oct 2008)

Log Message:
-----------
Author: Kev <[EMAIL PROTECTED]>
Description:

Finish implementing the table registration and unregistration routines.
Also, implement mode_str_info(), for building the strings used in
RPL_MYINFO; mode_str_modes(), for building the strings used in the
CHANMODES parameter of RPL_ISUPPORT; and mode_str_prefix(), for building
the strings used in the PREFIX parameter of RPL_ISUPPORT.

Modified Paths:
--------------
    ircu2/branches/mode/ChangeLog
    ircu2/branches/mode/include/mode.h
    ircu2/branches/mode/ircd/mode-compat.c
    ircu2/branches/mode/ircd/mode.c

Modified: ircu2/branches/mode/ChangeLog
===================================================================
--- ircu2/branches/mode/ChangeLog       2008-10-03 03:49:25 UTC (rev 1884)
+++ ircu2/branches/mode/ChangeLog       2008-10-04 03:29:22 UTC (rev 1885)
@@ -1,3 +1,14 @@
+2008-10-03  Kevin L. Mitchell  <[EMAIL PROTECTED]>
+
+       * include/mode.h: define MODE_DESC_CHECK() and MODE_LIST_CHECK()
+       macros; declare mode_str_info(), mode_str_modes(), and
+       mode_str_prefix()
+
+       * ircd/mode-compat.c: +o and +v also maintain lists...
+
+       * ircd/mode.c: implement *_reg() and *_unreg() routines; implement
+       mode_str_info(), mode_str_modes(), and mode_str_prefix()
+
 2008-10-02  Kevin L. Mitchell  <[EMAIL PROTECTED]>
 
        * ircd/mode-compat.c: implement mode_compat_init()

Modified: ircu2/branches/mode/include/mode.h
===================================================================
--- ircu2/branches/mode/include/mode.h  2008-10-03 03:49:25 UTC (rev 1884)
+++ ircu2/branches/mode/include/mode.h  2008-10-04 03:29:22 UTC (rev 1885)
@@ -81,6 +81,9 @@
   { REGENT_INIT(MODE_DESC_MAGIC, (name)), (sw), (pfx), 0, (desc),      \
     (flags) | (((prio) & 0x0f) << 16) }
 
+/** Check the mode descriptor for validity. */
+#define MODE_DESC_CHECK(md)    REGENT_CHECK((md), MODE_DESC_MAGIC)
+
 /** Mode maintains a list. */
 #define MDFLAG_LIST            0x80000000
 /** Mode should not be propagated to other servers. */
@@ -166,6 +169,10 @@
                (unreg_t) _mode_desc_unreg), (offset),                  \
     KEYSPACE_INIT(MAX_MODES, 0, 0, 0) }
 
+/** Check the mode list for validity. */
+#define MODE_LIST_CHECK(ml)    (REGTAB_CHECK(ml) &&                    \
+                                reg_magic(&(ml->ml_table)) == MODE_DESC_MAGIC)
+
 /** Describes the set of modes set on a specific channel, user, etc. */
 DECLARE_FLAGSET(ModeSet, MAX_MODES);
 
@@ -226,4 +233,11 @@
 /* Initialize mode subsystem. */
 extern void mode_init(void);
 
+/* Build mode list strings for RPL_MYINFO. */
+extern char* mode_str_info(modelist_t* ml, char* buf, int* len, int args);
+/* Build mode list strings for CHANMODES in RPL_ISUPPORT. */
+extern char* mode_str_modes(modelist_t* ml, char* buf, int* len);
+/* Build prefix string for PREFIX in RPL_ISUPPORT. */
+extern char* mode_str_prefix(modelist_t* ml, char* buf, int* len);
+
 #endif /* INCLUDED_mode_h */

Modified: ircu2/branches/mode/ircd/mode-compat.c
===================================================================
--- ircu2/branches/mode/ircd/mode-compat.c      2008-10-03 03:49:25 UTC (rev 
1884)
+++ ircu2/branches/mode/ircd/mode-compat.c      2008-10-04 03:29:22 UTC (rev 
1885)
@@ -34,11 +34,11 @@
  */
 modedesc_t _cmodes[] = {
   MODE_DESC_INIT("CHANOP",     'o', "Channel operator.",
-                MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP,
-                '@', 15),
+                MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP |
+                MDFLAG_LIST, '@', 15),
   MODE_DESC_INIT("VOICE",      'v', "Has voice.",
-                MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP,
-                '+', 0),
+                MDPAR_ARG_CLI | MDPAR_TYPE_REQARG | MDPOL_AUTHZ_CHOP |
+                MDFLAG_LIST, '+', 0),
   MODE_DESC_INIT("PRIVATE",    'p', "Channel is private.",
                 MDPOL_AUTHZ_CHOP, 0, 0),
   MODE_DESC_INIT("SECRET",     's', "Channel is secret.",

Modified: ircu2/branches/mode/ircd/mode.c
===================================================================
--- ircu2/branches/mode/ircd/mode.c     2008-10-03 03:49:25 UTC (rev 1884)
+++ ircu2/branches/mode/ircd/mode.c     2008-10-04 03:29:22 UTC (rev 1885)
@@ -26,24 +26,60 @@
 #include "ircd_log.h"
 #include "register.h"
 
+#include <string.h>
+
 /** Initialize a mode list.
  * @param[in] table Pointer to md_table.
- * @param[in] ml Mode list to verify.
+ * @param[in,out] ml Mode list to verify.
  * @return 0 for valid mode list, non-zero otherwise.
  */
 static int
 ml_reg(regtab_t* table, modelist_t* ml)
 {
+  /* Sanity-check the mode list */
+  if (reg_magic(&ml->ml_table) != MODE_DESC_MAGIC ||
+      reg_reg(&ml->ml_table) != _mode_desc_reg ||
+      reg_unreg(&ml->ml_table) != _mode_desc_unreg)
+    return -2;
+
+  /* Initialize the keyspace and the maps */
+  ks_init(&ml->ml_keyspace, MAX_MODES, 0, 0, ml);
+  memset(&ml->ml_smap, 0, sizeof(mode_desc_t*) * 256);
+  memset(&ml->ml_mmap, 0, sizeof(mode_desc_t*) * MAX_MODES);
+
+  return 0; /* all set! */
 }
 
+/** Remove all existing mode descriptors from a mode list.
+ * @param[in,out] ml Pointer to modelist_t.
+ * @param[in,out] md Pointer to modedesc_t.
+ * @param[in] extra Extra pointer passed to regtab_iter().
+ * @return 0 to continue iteration.
+ */
+static int
+ml_unreg_flush(modelist_t* ml, modedesc_t* md, void* extra)
+{
+  /* unregister the mode descriptor */
+  unregtab(ml, md);
+
+  return 0;
+}
+
 /** Clean up a mode list.
  * @param[in] table Pointer to md_table.
- * @param[in] ml Mode list to flush.
+ * @param[in,out] ml Mode list to flush.
  * @return 0 to accept unregistration.
  */
 static int
 ml_unreg(regtab_t* table, modelist_t* ml)
 {
+  /* Remove all descriptors from the table */
+  regtab_iter(&ml->ml_table, (regiter_t) ml_unreg_flush, 0);
+
+  /* Clean up the keyspace and clear the maps */
+  ks_clean(&ml->ml_keyspace);
+  memset(&ml->ml_smap, 0, sizeof(mode_desc_t*) * 256);
+  memset(&ml->ml_mmap, 0, sizeof(mode_desc_t*) * MAX_MODES);
 }
 
 /** Table of mode lists. */
@@ -51,23 +87,52 @@
                                       (reg_t) ml_reg, (unreg_t) ml_unreg);
 
 /** Assign mode and add to appropriate tables.
- * @param[in] table Pointer to mode list.
- * @param[in] md Mode descriptor to add.
+ * @param[in,out] ml Pointer to mode list.
+ * @param[in,out] md Mode descriptor to add.
  * @return 0 for valid mode descriptor, non-zero otherwise.
  */
 int
-_mode_desc_reg(regtab_t* table, modedesc_t* md)
+_mode_desc_reg(modelist_t* ml, modedesc_t* md)
 {
+  /* First, verify that the mode descriptor is valid */
+  if (!md->md_switch)
+    return -2;
+
+  /* Do we already have that switch registered? */
+  if (ml->ml_smap[md->md_switch])
+    return -3;
+
+  /* OK, let's reserve a mode from the keyspace */
+  if ((md->md_mode = ks_reserve(&ml->ml_keyspace)) == KEY_INVKEY)
+    return 1;
+
+  /* Enter the mode into the modelist maps */
+  ml->ml_smap[md->md_switch] = md;
+  ml->ml_mmap[md->md_mode] = md;
+
+  return 0;
 }
 
 /** Release mode and remove from tables.
- * @param[in] table Pointer to mode list.
+ * @param[in,out] ml Pointer to mode list.
  * @param[in] md Mode descriptor to remove.
  * @return 0 to accept unregistration.
  */
 int
-_mode_desc_unreg(regtab_t* table, modedesc_t* md)
+_mode_desc_unreg(modelist_t* ml, modedesc_t* md)
 {
+  /* Make sure the mode really is in the list... */
+  if (ml->ml_smap[md->md_switch] != md || ml->ml_mmap[md->md_mode] != md)
+    return -1;
+
+  /* Clear the modelist map entries */
+  ml->ml_smap[md->md_switch] = 0;
+  ml->ml_mmap[md->md_mode] = 0;
+
+  /* Return the key to the keyspace */
+  ks_release(&ml->ml_keyspace, md->md_mode);
+
+  return 0;
 }
 
 /** Initialize mode subsystem. */
@@ -76,3 +141,251 @@
 {
   reg(REG_TABLE, &md_table);
 }
+
+/** Current state of informative mode string buffer. */
+struct info_state {
+  char*                buf;            /**< String buffer. */
+  int          size;           /**< Size of buffer. */
+  int          len;            /**< Current length of buffer. */
+  int          args;           /**< If true, skip modes without arguments. */
+};
+
+/** Determine if a specific mode should be added to the informative
+ * mode string.
+ * @param[in] table Registration table modedesc_t is in.
+ * @param[in] md Mode descriptor.
+ * @param[in,out] is Info string state.
+ * @return 0 to continue iteration.
+ */
+static int
+mi_build(regtab_t* table, modedesc_t* md, struct info_state *is)
+{
+  assert(MODE_DESC_CHECK(md));
+
+  /* Check if we're including this mode */
+  if (!(md->md_flags & MDFLAG_ARGEXTENDED) &&
+      (md->md_flags & MDFLAG_VIS_MASK) < MDFLAG_VIS_SERV &&
+      (!is->args || (md->md_flags & MDPAR_TYPE_MASK) <= MDPAR_TYPE_OPTARG))
+    /* Add this mode to the buffer */
+    is->buf[is->len++] = md->md_switch;
+
+  return is->len >= is->size;
+}
+
+/** Assemble informative mode string for RPL_MYINFO.
+ * @param[in] ml Mode list to build mode string from.
+ * @param[out] buf Buffer in which to build informative mode string.
+ * @param[in,out] len Size of buffer; on return, length of string.
+ * @param[in] args If 1, select only modes with parameters.
+ * @return Buffer containing informative mode string.
+ */
+char*
+mode_str_info(modelist_t* ml, char* buf, int* len, int args)
+{
+  struct info_state is = { buf, 0, 0, args };
+
+  assert(MODE_LIST_CHECK(ml));
+  assert(buf);
+  assert(len);
+
+  /* Set up the full info */
+  is.size = *len;
+
+  /* Now, let's iterate over all the mode descriptors */
+  if (regtab_iter(&ml->ml_table, (regiter_t) mi_build, &is))
+    return 0; /* some kind of failure occurred */
+
+  /* Terminate the buffer and store the new size */
+  is.buf[is.len] = '\0';
+  *len = is.len;
+
+  return is.buf; /* return the buffer */
+}
+
+/** Current state of mode description accumulation. */
+struct mode_state {
+  char*                buf;            /**< String buffer. */
+  int          size;           /**< Size of buffer. */
+  int          len;            /**< Current length of buffer. */
+  char*                types[4];       /**< Pointers to string components. */
+};
+
+/** Type of mode. */
+enum mode_type {
+  TYPE_A,      /**< Type A mode--maintains a list. */
+  TYPE_B,      /**< Type B mode--always has an argument. */
+  TYPE_C,      /**< Type C mode--only has an argument when set. */
+  TYPE_D       /**< Type D mode--no argument. */
+};
+
+/** Add specific modes to the appropriate string component.
+ * @param[in] table Registration table modedesc_t is in.
+ * @param[in] md Mode descriptor.
+ * @param[in,out] ms String buffer state.
+ * @return 0 to continue iteration.
+ */
+static int
+mm_build(regtab_t* table, modedesc_t* md, struct mode_state *ms)
+{
+  enum mode_type type;
+
+  assert(MODE_DESC_CHECK(md));
+
+  /* Check if we need to omit this mode */
+  if ((md->md_flags & MDFLAG_ARGEXTENDED) ||
+      (md->md_flags & MDFLAG_VIS_MASK) >= MDFLAG_VIS_SERV ||
+      md->md_prefix)
+    return 0; /* skip this one */
+
+  /* Check the length... */
+  if (ms.len + 1 <= ms.size)
+    return -1;
+
+  /* Figure out which type of mode this is. */
+  if (md->md_flags & MDFLAG_LIST)
+    type = TYPE_A;
+  else
+    switch (md->md_flags & MDPAR_TYPE_MASK) {
+    case MDPAR_TYPE_SWITCH: /* plain switch */
+    case MDPAR_TYPE_OPTARG: /* shouldn't happen, but treat like plain switch */
+      type = TYPE_D;
+      break;
+
+    case MDPAR_TYPE_ADDARG: /* only has an argument when set */
+      type = TYPE_C;
+      break;
+
+    case MDPAR_TYPE_REQARG: /* requires an argument */
+      type = TYPE_B;
+      break;
+
+    default: /* uh... */
+      return 0;
+      break;
+    }
+
+  /* OK, let's shift the string over one position */
+  memmove(ms.types[type] + 1, ms.types[type],
+         ms.len + 1 - (ms.types[type] - ms.buf));
+
+  /* add this mode to the string */
+  *ms.types[type] = md->md_switch;
+
+  /* shift up the component pointers... */
+  for (; type <= TYPE_D; type++)
+    ms.types[type]++;
+
+  return 0;
+}
+
+/** Assemble string for CHANMODES component of RPL_ISUPPORT.
+ * @param[in] ml Mode list to build mode string from.
+ * @param[out] buf Buffer in which to build the string.
+ * @param[in,out] len Size of buffer; on return, length of string.
+ * @return Buffer containing modes string.
+ */
+char*
+mode_str_modes(modelist_t* ml, char* buf, int* len)
+{
+  struct mode_state ms = { buf, 0, 0, { 0, 0, 0, 0 } };
+
+  assert(MODE_LIST_CHECK(ml));
+  assert(buf);
+  assert(len);
+
+  /* Set up the full info */
+  ms.size = *len;
+
+  /* Do we have enough space for the initial set-up? */
+  if (ms.size < 4)
+    return 0;
+
+  /* OK, initialize the buffer appropriately */
+  *(ms.types[TYPE_A] = buf + 0) = ',';
+  *(ms.types[TYPE_B] = buf + 1) = ',';
+  *(ms.types[TYPE_C] = buf + 2) = ',';
+  *(ms.types[TYPE_D] = buf + 3) = '\0';
+
+  /* Current length: 3 */
+  ms.len = 3;
+
+  /* Now let's iterate over all the mode descriptors */
+  if (regtab_iter(&ml->ml_table, (regiter_t) ms_build, &ms))
+    return 0; /* some kind of failure occurred */
+
+  return ms.buf; /* return the buffer */
+}
+
+/** Convert a flag value with prefix priority into just the priority. */
+#define flag2prio(f)   (((f) & MDFLAG_PRIO) >> 16)
+
+/** Current state of prefix accumulation. */
+struct pfx_state {
+  int          count;          /**< Number of modes to enter. */
+  int          max;            /**< Maximum number of modes to enter. */
+  modedesc_t*  modes[flag2prio(MDFLAG_PRIO) + 1];
+                               /**< Modes contributing to prefix. */
+};
+
+/** Determine if a specific mode participates in the prefix calculation.
+ * @param[in] table Registration table modedesc_t is in.
+ * @param[in] md Mode descriptor.
+ * @param[in,out] ps Prefix string state.
+ * @return 0 to continue iteration, non-zero if there is a problem.
+ */
+static int
+mp_build(regtab_t* table, modedesc_t* md, struct pfx_state *ps)
+{
+  assert(MODE_DESC_CHECK(md));
+
+  /* Does this mode have an associated prefix? */
+  if (md->md_prefix) {
+    if (ps->modes[flag2prio(md->md_flags)] || ps->count >= ps->max)
+      return -1; /* two modes of the same priority, or buffer too small */
+
+    ps->modes[flag2prio(md->md_flags)] = md; /* save it */
+    ps->count++;
+  }
+
+  return 0; /* keep iterating */
+}
+
+/** Assemble string for PREFIX component of RPL_ISUPPORT.
+ * @param[in] ml Mode list to build mode string from.
+ * @param[out] buf Buffer in which to build the string.
+ * @param[in,out] len Size of buffer; on return, length of string.
+ * @return Buffer containing prefix string.
+ */
+char*
+mode_str_prefix(modelist_t* ml, char* buf, int* len)
+{
+  struct pfx_state ps;
+  int i, j, offset;
+
+  assert(MODE_LIST_CHECK(ml));
+  assert(buf);
+  assert(len);
+
+  /* let's clear the status */
+  memset(&ps, 0, sizeof(ps));
+  ps.max = (*len - 3) / 2; /* -3 for '(', ')', and '\0' */
+
+  /* Iterate over all the mode descriptors */
+  if (regtab_iter(&ml->ml_table, (regiter_t) mp_build, &ps))
+    return 0; /* some kind of failure occurred */
+
+  /* We've now built the prefix list; set up the buffer */
+  buf[0] = '(';
+  buf[ps.count + 1] = ')';
+  offset = ps.count + 2;
+  buf[(*len = offset + ps.count)] = '\0';
+
+  /* Now fill it in */
+  for (j = 0, i = flag2prio(MDFLAG_PRIO); i >= 0; i--)
+    if (ps.modes[i]) {
+      buf[j + 1] = ps.modes[i]->md_switch;
+      buf[j + offset] = ps.modes[i]->md_prefix;
+    }
+
+  return buf; /* and return the assembled buffer */
+}


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.
_______________________________________________
Patches mailing list
[email protected]
http://undernet.sbg.org/mailman/listinfo/patches

Reply via email to