Browse Source

strset: set errno to ENOENT even if we return NULL.

It seems redundant: strset_test() and strset_clear() can only return NULL
when the string is not a member.  However, it became clear in writing
ccan/tsort that it's much more convenient for callers if we set errno
in this case too, so they can pass it up.
Rusty Russell 14 years ago
parent
commit
532cd74d55
3 changed files with 32 additions and 12 deletions
  1. 16 9
      ccan/strset/strset.c
  2. 5 2
      ccan/strset/strset.h
  3. 11 1
      ccan/strset/test/run.c

+ 16 - 9
ccan/strset/strset.c

@@ -61,12 +61,13 @@ char *strset_test(const struct strset *set, const char *member)
 {
 {
 	const char *str;
 	const char *str;
 
 
-	/* Empty set? */
-	if (!set->u.n)
-		return NULL;
-	str = closest(*set, member);
-	if (streq(member, str))
-		return (char *)str;
+	/* Non-empty set? */
+	if (set->u.n) {
+		str = closest(*set, member);
+		if (streq(member, str))
+			return (char *)str;
+	}
+	errno = ENOENT;
 	return NULL;
 	return NULL;
 }
 }
 
 
@@ -171,8 +172,10 @@ char *strset_clear(struct strset *set, const char *member)
 	u8 direction = 0; /* prevent bogus gcc warning. */
 	u8 direction = 0; /* prevent bogus gcc warning. */
 
 
 	/* Empty set? */
 	/* Empty set? */
-	if (!set->u.n)
+	if (!set->u.n) {
+		errno = ENOENT;
 		return NULL;
 		return NULL;
+	}
 
 
 	/* Find closest, but keep track of parent. */
 	/* Find closest, but keep track of parent. */
 	n = set;
 	n = set;
@@ -184,8 +187,10 @@ char *strset_clear(struct strset *set, const char *member)
 		if (unlikely(n->u.n->byte_num == (size_t)-1)) {
 		if (unlikely(n->u.n->byte_num == (size_t)-1)) {
 			const char *empty_str = n->u.n->child[0].u.s;
 			const char *empty_str = n->u.n->child[0].u.s;
 
 
-			if (member[0])
+			if (member[0]) {
+				errno = ENOENT;
 				return NULL;
 				return NULL;
+			}
 
 
 			/* Sew empty string back so remaining logic works */
 			/* Sew empty string back so remaining logic works */
 			free(n->u.n);
 			free(n->u.n);
@@ -203,8 +208,10 @@ char *strset_clear(struct strset *set, const char *member)
 	}
 	}
 
 
 	/* Did we find it? */
 	/* Did we find it? */
-	if (!streq(member, n->u.s))
+	if (!streq(member, n->u.s)) {
+		errno = ENOENT;
 		return NULL;
 		return NULL;
+	}
 
 
 	ret = n->u.s;
 	ret = n->u.s;
 
 

+ 5 - 2
ccan/strset/strset.h

@@ -52,7 +52,8 @@ static inline bool strset_empty(const struct strset *set)
  * @set: the set.
  * @set: the set.
  * @member: the string to search for.
  * @member: the string to search for.
  *
  *
- * Returns the member, or NULL if it isn't in the set.
+ * Returns the member, or NULL if it isn't in the set (and sets errno
+ * = ENOENT).
  *
  *
  * Example:
  * Example:
  *	if (strset_test(&set, "hello"))
  *	if (strset_test(&set, "hello"))
@@ -82,7 +83,9 @@ bool strset_set(struct strset *set, const char *member);
  * @set: the set.
  * @set: the set.
  * @member: the string to remove from the set.
  * @member: the string to remove from the set.
  *
  *
- * This returns the string which was passed to strset_set(), or NULL.
+ * This returns the string which was passed to strset_set(), or NULL if
+ * the string was not in the map (in which case it sets errno = ENOENT).
+ *
  * This means that if you allocated a string (eg. using strdup()), you can
  * This means that if you allocated a string (eg. using strdup()), you can
  * free it here.
  * free it here.
  *
  *

+ 11 - 1
ccan/strset/test/run.c

@@ -10,20 +10,25 @@ int main(void)
 	char *dup = strdup(str);
 	char *dup = strdup(str);
 
 
 	/* This is how many tests you plan to run */
 	/* This is how many tests you plan to run */
-	plan_tests(26);
+	plan_tests(36);
 
 
 	strset_init(&set);
 	strset_init(&set);
 
 
 	ok1(!strset_test(&set, str));
 	ok1(!strset_test(&set, str));
+	ok1(errno == ENOENT);
 	ok1(!strset_test(&set, none));
 	ok1(!strset_test(&set, none));
+	ok1(errno == ENOENT);
 	ok1(!strset_clear(&set, str));
 	ok1(!strset_clear(&set, str));
+	ok1(errno == ENOENT);
 	ok1(!strset_clear(&set, none));
 	ok1(!strset_clear(&set, none));
+	ok1(errno == ENOENT);
 
 
 	ok1(strset_set(&set, str));
 	ok1(strset_set(&set, str));
 	ok1(strset_test(&set, str));
 	ok1(strset_test(&set, str));
 	/* We compare the string, not the pointer. */
 	/* We compare the string, not the pointer. */
 	ok1(strset_test(&set, dup));
 	ok1(strset_test(&set, dup));
 	ok1(!strset_test(&set, none));
 	ok1(!strset_test(&set, none));
+	ok1(errno == ENOENT);
 
 
 	/* Add of duplicate should fail. */
 	/* Add of duplicate should fail. */
 	ok1(!strset_set(&set, dup));
 	ok1(!strset_set(&set, dup));
@@ -32,17 +37,22 @@ int main(void)
 	/* Delete should return original string. */
 	/* Delete should return original string. */
 	ok1(strset_clear(&set, dup) == str);
 	ok1(strset_clear(&set, dup) == str);
 	ok1(!strset_test(&set, str));
 	ok1(!strset_test(&set, str));
+	ok1(errno == ENOENT);
 	ok1(!strset_test(&set, none));
 	ok1(!strset_test(&set, none));
+	ok1(errno == ENOENT);
 
 
 	/* Try insert and delete of empty string. */
 	/* Try insert and delete of empty string. */
 	ok1(strset_set(&set, none));
 	ok1(strset_set(&set, none));
 	ok1(strset_test(&set, none));
 	ok1(strset_test(&set, none));
 	ok1(!strset_test(&set, str));
 	ok1(!strset_test(&set, str));
+	ok1(errno == ENOENT);
 
 
 	/* Delete should return original string. */
 	/* Delete should return original string. */
 	ok1(strset_clear(&set, "") == none);
 	ok1(strset_clear(&set, "") == none);
 	ok1(!strset_test(&set, str));
 	ok1(!strset_test(&set, str));
+	ok1(errno == ENOENT);
 	ok1(!strset_test(&set, none));
 	ok1(!strset_test(&set, none));
+	ok1(errno == ENOENT);
 
 
 	/* Both at once... */
 	/* Both at once... */
 	ok1(strset_set(&set, none));
 	ok1(strset_set(&set, none));