コード例 #1
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
/* Remove all aliases for a standard attr. */
static int
free_standard_attr_aliases(ATTR *a)
{
  bool found_alias;
  ATTR *curr;
  const char *aliasname;
  int count = 0;

  /* Annoyingly convoluted because the ptab_delete will screw with the
   * counter used by ptab_nextextry_new */
  do {
    found_alias = 0;
    curr = ptab_firstentry_new(&ptab_attrib, &aliasname);
    for (; curr; curr = ptab_nextentry_new(&ptab_attrib, &aliasname)) {
      if (!strcmp(AL_NAME(curr), AL_NAME(a)) &&
          strcmp(AL_NAME(curr), aliasname)) {
        found_alias = 1;
        ptab_delete(&ptab_attrib, aliasname);
        count++;
        break;
      }
    }
  } while (found_alias);

  return count;
}
コード例 #2
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
/** Free all memory used by a standard attribute, and remove it from the hash
 * table if necessary.
 * \param a attr to remove
 * \param inserted has the attr been inserted into the hash table already?
 * \retval number of entries (including aliases) removed from the hash table
 */
static int
free_standard_attr(ATTR *a, bool inserted)
{
  int count = 0;
  if (!a) {
    return count;
  }

  /* If the attr has no name, there's no way it can be in the hash table */
  if (AL_NAME(a)) {
    if (inserted) {
      count = free_standard_attr_aliases(a) + 1;
      ptab_delete(&ptab_attrib, AL_NAME(a));
    }
    free((char *) AL_NAME(a));
  }

  if (a->data != NULL_CHUNK_REFERENCE) {
    chunk_delete(a->data);
  }

  mush_free(a, "ATTR");

  return count;

}
コード例 #3
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
/** Return a list of standard attributes.
 * This functions returns the list of standard attributes, separated by
 * spaces, in a statically allocated buffer.
 */
char *
list_attribs(void)
{
  ATTR *ap;
  const char *ptrs[BUFFER_LEN / 2];
  static char buff[BUFFER_LEN];
  char *bp;
  const char *name;
  int nptrs = -1, i;

  for (ap = ptab_firstentry_new(&ptab_attrib, &name);
       ap; ap = ptab_nextentry_new(&ptab_attrib, &name)) {
    if (strcmp(name, AL_NAME(ap)))
      continue;
    ptrs[++nptrs] = AL_NAME(ap);
  }
  bp = buff;
  if (nptrs >= 0)
    safe_str(ptrs[0], buff, &bp);
  for (i = 1; i < nptrs; i++) {
    safe_chr(' ', buff, &bp);
    safe_str(ptrs[i], buff, &bp);
  }
  *bp = '\0';
  return buff;
}
コード例 #4
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
/** Decompile the standard attribute table, as per \@attribute/decompile
 * \param player The enactor
 * \param pattern Wildcard pattern of attrnames to decompile
 * \param retroactive Include the /retroactive switch?
*/
void
do_decompile_attribs(dbref player, char *pattern, int retroactive)
{
  ATTR *ap;
  const char *name;

  notify(player, T("@@ Standard Attributes:"));
  for (ap = ptab_firstentry_new(&ptab_attrib, &name);
       ap; ap = ptab_nextentry_new(&ptab_attrib, &name)) {
    if (strcmp(name, AL_NAME(ap)))
      continue;
    if (pattern && *pattern && !quick_wild(pattern, AL_NAME(ap)))
      continue;
    notify_format(player, "@attribute/access%s %s=%s",
                  (retroactive ? "/retroactive" : ""),
                  AL_NAME(ap), privs_to_string(attr_privs_view, AL_FLAGS(ap)));
    if (ap->flags & AF_RLIMIT) {
      notify_format(player, "@attribute/limit %s=%s", AL_NAME(ap),
                    display_attr_limit(ap));
    } else if (ap->flags & AF_ENUM) {
      notify_format(player, "@attribute/enum %s=%s", AL_NAME(ap),
                    display_attr_limit(ap));
    }
  }
}
コード例 #5
0
ファイル: atr_tab.c プロジェクト: Syntroth/redpill_mush
/** Display information on an attribute from the table.
 * \verbatim
 * Top-level function for @attribute.
 * \endverbatim
 * \param player the enactor.
 * \param name the name of the attribute.
 */
void
do_attribute_info(dbref player, char *name)
{
  ATTR *ap;
  if (!name || !*name) {
    notify(player, T("Which attribute do you mean?"));
    return;
  }

  /* Is this attribute in the table? */

  if (*name == '@')
    name++;

  ap = aname_hash_lookup(name);
  if (!ap) {
    notify(player, T("That attribute isn't in the attribute table"));
    return;
  }
  notify_format(player, "%9s: %s", T("Attribute"), AL_NAME(ap));
  if (ap->flags & AF_RLIMIT) {
    notify_format(player, "%9s: %s", T("Limit"), display_attr_limit(ap));
  } else if (ap->flags & AF_ENUM) {
    notify_format(player, "%9s: %s", T("Enum"), display_attr_limit(ap));
  }
  notify_format(player,
                "%9s: %s", T("Flags"), privs_to_string(attr_privs_view,
                                                       AL_FLAGS(ap)));
  notify_format(player, "%9s: %s", T("Creator"), unparse_dbref(AL_CREATOR(ap)));
  return;
}
コード例 #6
0
ファイル: atr_tab.c プロジェクト: Syntroth/redpill_mush
/* Add a new, or restrict an existing, standard attribute from cnf file */
int
cnf_attribute_access(char *attrname, char *opts)
{
  ATTR *a;
  privbits flags = 0;

  upcasestr(attrname);
  if (!good_atr_name(attrname))
    return 0;

  if (strcasecmp(opts, "none")) {
    flags = list_to_privs(attr_privs_set, opts, 0);
    if (!flags)
      return 0;
  }

  a = (ATTR *) ptab_find_exact(&ptab_attrib, attrname);
  if (a) {
    if (AF_Internal(a))
      return 0;
  } else {
    a = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR");
    if (!a)
      return 0;
    AL_NAME(a) = strdup(attrname);
    a->data = NULL_CHUNK_REFERENCE;
    ptab_insert_one(&ptab_attrib, attrname, a);
  }
  AL_FLAGS(a) = flags;
  AL_CREATOR(a) = GOD;
  return 1;
}
コード例 #7
0
static void
grep_add_attr(char *buff, char **bp, dbref player, int count, ATTR *attr,
              char *atrval)
{

  if (buff) {
    if (count)
      safe_chr(' ', buff, bp);
    safe_str(AL_NAME(attr), buff, bp);
  } else {
    notify_format(player, "%s%s [#%d%s]:%s %s",
                  ANSI_HILITE, AL_NAME(attr),
                  Owner(AL_CREATOR(attr)),
                  privs_to_letters(attr_privs_view, AL_FLAGS(attr)),
                  ANSI_END, atrval);
  }
}
コード例 #8
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
void
attr_write_all(PENNFILE *f)
{
  int attrcount = 0, aliascount = 0;
  ATTR *a;
  const char *attrname;
  char *data;

  for (a = ptab_firstentry_new(&ptab_attrib, &attrname); a;
       a = ptab_nextentry_new(&ptab_attrib, &attrname)) {
    if (!strcmp(attrname, AL_NAME(a)))
      attrcount++;
    else
      aliascount++;
  }

  db_write_labeled_int(f, "attrcount", attrcount);
  for (a = ptab_firstentry_new(&ptab_attrib, &attrname); a;
       a = ptab_nextentry_new(&ptab_attrib, &attrname)) {
    if (strcmp(attrname, AL_NAME(a)))
      continue;                 /* skip aliases */
    db_write_labeled_string(f, " name", AL_NAME(a));
    db_write_labeled_string(f, "  flags",
                            privs_to_string(attr_privs_db, AL_FLAGS(a)));
    db_write_labeled_dbref(f, "  creator", AL_CREATOR(a));
    data = atr_value(a);
    db_write_labeled_string(f, "  data", data);
  }

  db_write_labeled_int(f, "attraliascount", aliascount);
  for (a = ptab_firstentry_new(&ptab_attrib, &attrname); a;
       a = ptab_nextentry_new(&ptab_attrib, &attrname)) {
    if (!strcmp(attrname, AL_NAME(a)))
      continue;                 /* skip non-aliases */
    db_write_labeled_string(f, " name", AL_NAME(a));
    db_write_labeled_string(f, "  alias", attrname);
  }

}
コード例 #9
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
static void
display_attr_info(dbref player, ATTR *ap)
{

  notify_format(player, "%9s: %s", T("Attribute"), AL_NAME(ap));
  if (ap->flags & AF_RLIMIT) {
    notify_format(player, "%9s: %s", T("Limit"), display_attr_limit(ap));
  } else if (ap->flags & AF_ENUM) {
    notify_format(player, "%9s: %s", T("Enum"), display_attr_limit(ap));
  }
  notify_format(player,
                "%9s: %s", T("Flags"), privs_to_string(attr_privs_view,
                                                       AL_FLAGS(ap)));
  notify_format(player, "%9s: %s", T("Creator"), unparse_dbref(AL_CREATOR(ap)));
  return;
}
コード例 #10
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
/** Add a new attribute. Called from db.c to add new attributes
 * to older databases which have their own attr table.
 * \param name name of attr to add
 * \param flags attribute flags (AF_*)
 */
void
add_new_attr(char *name, uint32_t flags)
{
  ATTR *ap;
  ap = (ATTR *) ptab_find_exact(&ptab_attrib, name);
  if (ap || !good_atr_name(name))
    return;

  ap = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR");
  if (!ap) {
    do_log(LT_ERR, 0, 0, "add_new_attr: unable to malloc ATTR");
    return;
  }
  AL_NAME(ap) = strdup(name);
  ap->data = NULL_CHUNK_REFERENCE;
  AL_FLAGS(ap) = flags;
  AL_CREATOR(ap) = 0;
  ptab_insert_one(&ptab_attrib, name, ap);

}
コード例 #11
0
ファイル: atr_tab.c プロジェクト: Syntroth/redpill_mush
/** Rename an attribute in the attribute table.
 * \verbatim
 * Top-level function for @attrib/rename.
 * \endverbatim
 * \param player the enactor.
 * \param old the name of the attribute to rename.
 * \param newname the new name (surprise!)
 */
void
do_attribute_rename(dbref player, char *old, char *newname)
{
  ATTR *ap;
  if (!old || !*old || !newname || !*newname) {
    notify(player, T("Which attributes do you mean?"));
    return;
  }
  upcasestr(old);
  upcasestr(newname);
  /* Is the new name valid? */
  if (!good_atr_name(newname)) {
    notify(player, T("Invalid attribute name."));
    return;
  }
  /* Is the new name already in use? */
  ap = (ATTR *) ptab_find_exact(&ptab_attrib, newname);
  if (ap) {
    notify_format(player,
                  T("The name %s is already used in the attribute table."),
                  newname);
    return;
  }
  /* Is the old name a real attribute? */
  ap = (ATTR *) ptab_find_exact(&ptab_attrib, old);
  if (!ap) {
    notify(player, T("That attribute isn't in the attribute table"));
    return;
  }
  /* Ok, take it out and put it back under the new name */
  ptab_delete(&ptab_attrib, old);
  /*  This causes a slight memory leak if you rename an attribute
     added via /access. But that doesn't happen often. Will fix
     someday.  */
  AL_NAME(ap) = strdup(newname);
  ptab_insert_one(&ptab_attrib, newname, ap);
  notify_format(player,
                T("Renamed %s to %s in attribute table."), old, newname);
  return;
}
コード例 #12
0
ファイル: atr_tab.c プロジェクト: Syntroth/redpill_mush
/** Return a list of standard attributes.
 * This functions returns the list of standard attributes, separated by
 * spaces, in a statically allocated buffer.
 */
char *
list_attribs(void)
{
  ATTR *ap;
  const char *ptrs[BUFFER_LEN / 2];
  static char buff[BUFFER_LEN];
  char *bp;
  int nptrs = 0, i;

  ap = (ATTR *) ptab_firstentry(&ptab_attrib);
  ptrs[0] = "";
  while (ap) {
    ptrs[nptrs++] = AL_NAME(ap);
    ap = (ATTR *) ptab_nextentry(&ptab_attrib);
  }
  bp = buff;
  safe_str(ptrs[0], buff, &bp);
  for (i = 1; i < nptrs; i++) {
    safe_chr(' ', buff, &bp);
    safe_str(ptrs[i], buff, &bp);
  }
  *bp = '\0';
  return buff;
}
コード例 #13
0
ファイル: utils.c プロジェクト: kymoon/pennmush
/** Populate a ufun_attrib struct from an obj/attr pair.
 * \verbatim Given an attribute [<object>/]<name> pair (which may include #lambda),
 * fetch its value, owner (thing), and pe_flags, and store in the struct
 * pointed to by ufun
 * \endverbatim
 * \param attrstring The obj/name of attribute.
 * \param executor Dbref of the executing object.
 * \param ufun Pointer to an allocated ufun_attrib struct to fill in.
 * \param flags A bitwise or of desired UFUN_* flags.
 * \return 0 on failure, true on success.
 */
bool
fetch_ufun_attrib(const char *attrstring, dbref executor, ufun_attrib * ufun,
                  int flags)
{
  char *thingname, *attrname;
  char astring[BUFFER_LEN];
  ATTR *attrib;

  if (!ufun)
    return 0;

  ufun->contents[0] = '\0';
  ufun->errmess = (char *) "";
  ufun->thing = executor;
  ufun->pe_flags = PE_UDEFAULT;
  ufun->ufun_flags = flags;

  ufun->thing = executor;
  thingname = NULL;

  if (!attrstring)
    return 0;
  strncpy(astring, attrstring, BUFFER_LEN);

  /* Split obj/attr */
  if ((flags & UFUN_OBJECT) && ((attrname = strchr(astring, '/')) != NULL)) {
    thingname = astring;
    *(attrname++) = '\0';
  } else {
    attrname = astring;
  }

  if (thingname && (flags & UFUN_LAMBDA)
      && (strcasecmp(thingname, "#lambda") == 0
          || strncasecmp(thingname, "#apply", 6) == 0)) {
    /* It's a lambda. */

    ufun->ufun_flags &= ~UFUN_NAME;
    ufun->thing = executor;
    if (strcasecmp(thingname, "#lambda") == 0)
      mush_strncpy(ufun->contents, attrname, BUFFER_LEN);
    else {                      /* #apply */
      char *ucb = ufun->contents;
      unsigned nargs = 1, n;

      thingname += 6;

      if (*thingname)
        nargs = parse_uinteger(thingname);

      /* Limit between 1 and 10 arguments (%0-%9) */
      if (nargs == 0)
        nargs = 1;
      if (nargs > 10)
        nargs = 10;

      safe_str(attrname, ufun->contents, &ucb);
      safe_chr('(', ufun->contents, &ucb);
      for (n = 0; n < nargs; n++) {
        if (n > 0)
          safe_chr(',', ufun->contents, &ucb);
        safe_format(ufun->contents, &ucb, "%%%u", n);
      }
      safe_chr(')', ufun->contents, &ucb);
      *ucb = '\0';
    }

    ufun->attrname[0] = '\0';
    return 1;
  }

  if (thingname) {
    /* Attribute is on something else. */
    ufun->thing =
      noisy_match_result(executor, thingname, NOTYPE, MAT_EVERYTHING);
    if (!GoodObject(ufun->thing)) {
      ufun->errmess = (char *) "#-1 INVALID OBJECT";
      return 0;
    }
  }

  attrib = (ATTR *) atr_get(ufun->thing, upcasestr(attrname));
  if (attrib && AF_Internal(attrib)) {
    /* Regardless of whether we're doing permission checks, we should
     * never be showing internal attributes here */
    attrib = NULL;
  }

  /* An empty attrib is the same as no attrib. */
  if (attrib == NULL) {
    if (flags & UFUN_REQUIRE_ATTR) {
      if (!(flags & UFUN_IGNORE_PERMS) && !Can_Examine(executor, ufun->thing))
        ufun->errmess = e_atrperm;
      return 0;
    } else {
      mush_strncpy(ufun->attrname, attrname, ATTRIBUTE_NAME_LIMIT + 1);
      return 1;
    }
  }
  if (!(flags & UFUN_IGNORE_PERMS)
      && !Can_Read_Attr(executor, ufun->thing, attrib)) {
    ufun->errmess = e_atrperm;
    return 0;
  }
  if (!(flags & UFUN_IGNORE_PERMS)
      && !CanEvalAttr(executor, ufun->thing, attrib)) {
    ufun->errmess = e_perm;
    return 0;
  }

  /* DEBUG attributes */
  if (AF_NoDebug(attrib))
    ufun->pe_flags |= PE_NODEBUG;       /* No_Debug overrides Debug */
  else if (AF_Debug(attrib))
    ufun->pe_flags |= PE_DEBUG;

  if (flags & UFUN_NAME) {
    if (attrib->flags & AF_NONAME)
      ufun->ufun_flags &= ~UFUN_NAME;
    else if (attrib->flags & AF_NOSPACE)
      ufun->ufun_flags |= UFUN_NAME_NOSPACE;
  }

  /* Populate the ufun object */
  mush_strncpy(ufun->contents, atr_value(attrib), BUFFER_LEN);
  mush_strncpy(ufun->attrname, AL_NAME(attrib), ATTRIBUTE_NAME_LIMIT + 1);

  /* We're good */
  return 1;
}
コード例 #14
0
ファイル: atr_tab.c プロジェクト: Syntroth/redpill_mush
/** Add new standard attributes, or change permissions on them.
 * \verbatim
 * Given the name and permission string for an attribute, add it to
 * the attribute table (or modify the permissions if it's already
 * there). Permissions may be changed retroactively, which modifies
 * permissions on any copies of that attribute set on objects in the
 * database. This is the top-level code for @attribute/access.
 * \endverbatim
 * \param player the enactor.
 * \param name the attribute name.
 * \param perms a string of attribute permissions, space-separated.
 * \param retroactive if true, apply the permissions retroactively.
 */
void
do_attribute_access(dbref player, char *name, char *perms, int retroactive)
{
  ATTR *ap, *ap2;
  privbits flags = 0;
  int i;
  int insert = 0;

  /* Parse name and perms */
  if (!name || !*name) {
    notify(player, T("Which attribute do you mean?"));
    return;
  }
  if (strcasecmp(perms, "none")) {
    flags = list_to_privs(attr_privs_set, perms, 0);
    if (!flags) {
      notify(player, T("I don't understand those permissions."));
      return;
    }
  }
  upcasestr(name);
  /* Is this attribute already in the table? */
  ap = (ATTR *) ptab_find_exact(&ptab_attrib, name);
  if (ap) {
    if (AF_Internal(ap)) {
      /* Don't muck with internal attributes */
      notify(player, T("That attribute's permissions can not be changed."));
      return;
    }
  } else {
    /* Create fresh if the name is ok */
    if (!good_atr_name(name)) {
      notify(player, T("Invalid attribute name."));
      return;
    }
    insert = 1;
    ap = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR");
    if (!ap) {
      notify(player, T("Critical memory failure - Alert God!"));
      do_log(LT_ERR, 0, 0, "do_attribute_access: unable to malloc ATTR");
      return;
    }
    AL_NAME(ap) = strdup(name);
    ap->data = NULL_CHUNK_REFERENCE;
  }
  AL_FLAGS(ap) = flags;
  AL_CREATOR(ap) = player;

  /* Only insert when it's not already in the table */
  if (insert) {
    ptab_insert_one(&ptab_attrib, name, ap);
  }

  /* Ok, now we need to see if there are any attributes of this name
   * set on objects in the db. If so, and if we're retroactive, set
   * perms/creator
   */
  if (retroactive) {
    for (i = 0; i < db_top; i++) {
      if ((ap2 = atr_get_noparent(i, name))) {
        if (AL_FLAGS(ap2) & AF_ROOT)
          AL_FLAGS(ap2) = flags | AF_ROOT;
        else
          AL_FLAGS(ap2) = flags;
        AL_CREATOR(ap2) = player;
      }
    }
  }

  notify_format(player, T("%s -- Attribute permissions now: %s"), name,
                privs_to_string(attr_privs_view, flags));
}
コード例 #15
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
void
attr_read_all(PENNFILE *f)
{
  ATTR *a;
  int c, found, count = 0;
  char alias[BUFFER_LEN];

  /* Clear existing attributes */
  ptab_free(&ptab_attrib);

  ptab_start_inserts(&ptab_attrib);

  db_read_this_labeled_int(f, "attrcount", &count);
  for (found = 0;;) {

    c = penn_fgetc(f);
    penn_ungetc(c, f);

    if (c != ' ')
      break;

    found++;

    if ((a = attr_read(f)))
      ptab_insert(&ptab_attrib, a->name, a);
  }

  ptab_end_inserts(&ptab_attrib);

  if (found != count)
    do_rawlog(LT_ERR,
              "WARNING: Actual number of attrs (%d) different than expected count (%d).",
              found, count);

  /* Assumes we'll always have at least one alias */
  db_read_this_labeled_int(f, "attraliascount", &count);
  for (found = 0;;) {
    c = penn_fgetc(f);
    penn_ungetc(c, f);

    if (c != ' ')
      break;

    found++;

    if ((a = attr_alias_read(f, alias))) {
      upcasestr(alias);
      if (!good_atr_name(alias)) {
        do_rawlog(LT_ERR, "Bad attribute name on alias '%s' in db.", alias);
      } else if (aname_find_exact(strupper(alias))) {
        do_rawlog(LT_ERR,
                  "Unable to alias attribute '%s' to '%s' in db: alias already in use.",
                  AL_NAME(a), alias);
      } else if (!alias_attribute(AL_NAME(a), alias)) {
        do_rawlog(LT_ERR, "Unable to alias attribute '%s' to '%s' in db.",
                  AL_NAME(a), alias);
      }
    }
  }
  if (found != count)
    do_rawlog(LT_ERR,
              "WARNING: Actual number of attr aliases (%d) different than expected count (%d).",
              found, count);

  return;
}
コード例 #16
0
ファイル: atr_tab.c プロジェクト: HarryCordewener/pennmush
static ATTR *
attr_read(PENNFILE *f)
{
  ATTR *a;
  char *tmp;
  dbref d = GOD;
  privbits flags = 0;

  a = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR");
  if (!a) {
    mush_panic("Not enough memory to add attribute in attr_read()!");
    return NULL;
  }
  AL_NAME(a) = NULL;
  a->data = NULL_CHUNK_REFERENCE;
  AL_FLAGS(a) = 0;
  AL_CREATOR(a) = GOD;
  a->next = NULL;

  db_read_this_labeled_string(f, "name", &tmp);

  if (!good_atr_name(tmp)) {
    do_rawlog(LT_ERR, "Invalid attribute name '%s' in db.", tmp);
    (void) getstring_noalloc(f);        /* flags */
    (void) getstring_noalloc(f);        /* creator */
    (void) getstring_noalloc(f);        /* data */
    free_standard_attr(a, 0);
    return NULL;
  }

  AL_NAME(a) = strdup(tmp);
  db_read_this_labeled_string(f, "flags", &tmp);
  if (tmp && *tmp && strcasecmp(tmp, "none")) {
    flags = list_to_privs(attr_privs_db, tmp, 0);
    if (!flags) {
      do_rawlog(LT_ERR, "Invalid attribute flags for '%s' in db.", AL_NAME(a));
      free((char *) AL_NAME(a));
      (void) getstring_noalloc(f);      /* creator */
      (void) getstring_noalloc(f);      /* data */
      free_standard_attr(a, 0);
      return NULL;
    }
  }
  AL_FLAGS(a) = flags;

  db_read_this_labeled_dbref(f, "creator", &d);
  AL_CREATOR(a) = d;

  db_read_this_labeled_string(f, "data", &tmp);
  if (!tmp || !*tmp || !(AL_FLAGS(a) & (AF_ENUM | AF_RLIMIT))) {
    a->data = NULL_CHUNK_REFERENCE;
  } else if (AL_FLAGS(a) & AF_ENUM) {
    /* Store string as it is */
    char *t = compress(tmp);
    a->data = chunk_create(t, strlen(t), 0);
    free(t);
  } else if (AL_FLAGS(a) & AF_RLIMIT) {
    /* Need to validate regexp */
    char *t;
    pcre *re;
    const char *errptr;
    int erroffset;

    re = pcre_compile(tmp, PCRE_CASELESS, &errptr, &erroffset, tables);
    if (!re) {
      do_rawlog(LT_ERR, "Invalid regexp in limit for attribute '%s' in db.",
                AL_NAME(a));
      free_standard_attr(a, 0);
      return NULL;
    }
    pcre_free(re);              /* don't need it, just needed to check it */

    t = compress(tmp);
    a->data = chunk_create(t, strlen(t), 0);
    free(t);
  }

  return a;
}