/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009, 2011, 2012, 2016 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <config.h>
-#include <data/attributes.h>
+#include "data/attributes.h"
+
#include <assert.h>
#include <string.h>
-#include <libpspp/array.h>
-#include <libpspp/hash-functions.h>
-#include "xalloc.h"
+
+#include "libpspp/array.h"
+#include "libpspp/compiler.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
+
+#include "gl/xalloc.h"
/* A custom attribute of the sort maintained by the DATAFILE
ATTRIBUTE and VARIABLE ATTRIBUTE commands.
case-insensitively, or a null pointer if SET does not contain
an attribute with that name. */
struct attribute *
-attrset_lookup (struct attrset *set, const char *name)
+attrset_lookup (const struct attrset *set, const char *name)
{
- struct attribute *attr;
+ const struct attribute *attr;
HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
- hsh_hash_case_string (name), &set->map)
- if (!strcasecmp (attribute_get_name (attr), name))
+ utf8_hash_case_string (name, 0), &set->map)
+ if (!utf8_strcasecmp (attribute_get_name (attr), name))
break;
- return attr;
+ return CONST_CAST (struct attribute *, attr);
+}
+
+/* Adds ATTR to SET. Succeeds and returns true if SET does not already contain
+ an attribute with the same name (matched case insensitively); otherwise
+ fails and returns false. On success only, ownership of ATTR is transferred
+ to SET. */
+bool
+attrset_try_add (struct attrset *set, struct attribute *attr)
+{
+ const char *name = attribute_get_name (attr);
+ if (attrset_lookup (set, name))
+ return false;
+ hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0));
+ return true;
}
/* Adds ATTR to SET, which must not already contain an attribute
void
attrset_add (struct attrset *set, struct attribute *attr)
{
- const char *name = attribute_get_name (attr);
- assert (attrset_lookup (set, name) == NULL);
- hmap_insert (&set->map, &attr->node, hsh_hash_case_string (name));
+ bool ok UNUSED = attrset_try_add (set, attr);
+ assert (ok);
}
/* Deletes any attribute from SET that matches NAME
iterator->node = hmap_next (&set->map, iterator->node);
return iterator_data (iterator);
}
+
+static int
+compare_attribute_by_name (const void *a_, const void *b_)
+{
+ const struct attribute *const *a = a_;
+ const struct attribute *const *b = b_;
+
+ return strcmp ((*a)->name, (*b)->name);
+}
+
+/* Allocates and returns an array of pointers to attributes
+ that is sorted by attribute name. The array has
+ 'attrset_count (SET)' elements. The caller is responsible for
+ freeing the array. */
+struct attribute **
+attrset_sorted (const struct attrset *set)
+{
+ if (set != NULL && attrset_count (set) > 0)
+ {
+ struct attribute **attrs;
+ struct attribute *attr;
+ size_t i;
+
+ attrs = xmalloc (attrset_count (set) * sizeof *attrs);
+ i = 0;
+ HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
+ attrs[i++] = attr;
+ assert (i == attrset_count (set));
+ qsort (attrs, attrset_count (set), sizeof *attrs,
+ compare_attribute_by_name);
+ return attrs;
+ }
+ else
+ return NULL;
+}