Commit 0c9eacf3d2c83256736a5bb2a240e73afd13d55f

Vicent Marti 2012-08-02T01:15:24

attr: Do not export variables externally Fixes #824 Exporting variables in a dynamic library is a PITA. Let's keep these values internally and wrap them through a helper method. This doesn't break the external API. @arrbee, aren't you glad I turned the `GIT_ATTR_` macros into function macros? :sparkles:

diff --git a/include/git2/attr.h b/include/git2/attr.h
index fad7183..451eb66 100644
--- a/include/git2/attr.h
+++ b/include/git2/attr.h
@@ -30,7 +30,7 @@ GIT_BEGIN_DECL
  * Then for file `xyz.c` looking up attribute "foo" gives a value for
  * which `GIT_ATTR_TRUE(value)` is true.
  */
-#define GIT_ATTR_TRUE(attr)		((attr) == git_l_attr__true)
+#define GIT_ATTR_TRUE(attr)	(git_attr_value(attr) == GIT_ATTR_TRUE_T)
 
 /**
  * GIT_ATTR_FALSE checks if an attribute is set off.  In core git
@@ -44,7 +44,7 @@ GIT_BEGIN_DECL
  * Then for file `zyx.h` looking up attribute "foo" gives a value for
  * which `GIT_ATTR_FALSE(value)` is true.
  */
-#define GIT_ATTR_FALSE(attr)	((attr) == git_l_attr__false)
+#define GIT_ATTR_FALSE(attr) (git_attr_value(attr) == GIT_ATTR_FALSE_T)
 
 /**
  * GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified.  This
@@ -62,7 +62,7 @@ GIT_BEGIN_DECL
  * file `onefile.rb` or looking up "bar" on any file will all give
  * `GIT_ATTR_UNSPECIFIED(value)` of true.
  */
-#define GIT_ATTR_UNSPECIFIED(attr)	(!(attr) || (attr) == git_l_attr__unset)
+#define GIT_ATTR_UNSPECIFIED(attr) (git_attr_value(attr) == GIT_ATTR_UNSPECIFIED_T)
 
 /**
  * GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as
@@ -74,13 +74,29 @@ GIT_BEGIN_DECL
  * Given this, looking up "eol" for `onefile.txt` will give back the
  * string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true.
  */
-#define GIT_ATTR_HAS_VALUE(attr) \
-	((attr) && (attr) != git_l_attr__unset && \
-	 (attr) != git_l_attr__true && (attr) != git_attr__false)
+#define GIT_ATTR_HAS_VALUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_T)
 
-GIT_EXTERN(const char *) git_l_attr__true;
-GIT_EXTERN(const char *) git_l_attr__false;
-GIT_EXTERN(const char *) git_l_attr__unset;
+typedef enum {
+	GIT_ATTR_UNSPECIFIED_T = 0,
+	GIT_ATTR_TRUE_T,
+	GIT_ATTR_FALSE_T,
+	GIT_ATTR_VALUE_T,
+} git_attr_t;
+
+/*
+ *	Return the value type for a given attribute.
+ *
+ *	This can be either `TRUE`, `FALSE`, `UNSPECIFIED` (if the attribute
+ *	was not set at all), or `VALUE`, if the attribute was set to
+ *	an actual string.
+ *
+ *	If the attribute has a `VALUE` string, it can be accessed normally
+ *	as a NULL-terminated C string.
+ *
+ *	@param attr The attribute
+ *	@return the value type for the attribute
+ */
+git_attr_t git_attr_value(const char *attr);
 
 /**
  * Check attribute flags: Reading values from index and working directory.
diff --git a/src/attr.c b/src/attr.c
index 6fbd005..1c51199 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -5,6 +5,25 @@
 
 GIT__USE_STRMAP;
 
+const char *git_attr__true  = "[internal]__TRUE__";
+const char *git_attr__false = "[internal]__FALSE__";
+const char *git_attr__unset = "[internal]__UNSET__";
+
+git_attr_t git_attr_value(const char *attr)
+{
+	if (attr == NULL || attr == git_attr__unset)
+		return GIT_ATTR_UNSPECIFIED_T;
+
+	if (attr == git_attr__true)
+		return GIT_ATTR_TRUE_T;
+
+	if (attr == git_attr__false)
+		return GIT_ATTR_FALSE_T;
+
+	return GIT_ATTR_VALUE_T;
+}
+
+
 static int collect_attr_files(
 	git_repository *repo,
 	uint32_t flags,
diff --git a/src/attr_file.c b/src/attr_file.c
index 837c42d..966da40 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -5,10 +5,6 @@
 #include "git2/tree.h"
 #include <ctype.h>
 
-const char *git_l_attr__true  = "[internal]__TRUE__";
-const char *git_l_attr__false = "[internal]__FALSE__";
-const char *git_l_attr__unset = "[internal]__UNSET__";
-
 static int sort_by_hash_and_name(const void *a_raw, const void *b_raw);
 static void git_attr_rule__clear(git_attr_rule *rule);
 
@@ -493,14 +489,14 @@ int git_attr_assignment__parse(
 		}
 
 		assign->name_hash = 5381;
-		assign->value = git_l_attr__true;
+		assign->value = git_attr__true;
 
 		/* look for magic name prefixes */
 		if (*scan == '-') {
-			assign->value = git_l_attr__false;
+			assign->value = git_attr__false;
 			scan++;
 		} else if (*scan == '!') {
-			assign->value = git_l_attr__unset; /* explicit unspecified state */
+			assign->value = git_attr__unset; /* explicit unspecified state */
 			scan++;
 		} else if (*scan == '#') /* comment rest of line */
 			break;
@@ -536,7 +532,7 @@ int git_attr_assignment__parse(
 		}
 
 		/* expand macros (if given a repo with a macro cache) */
-		if (repo != NULL && assign->value == git_l_attr__true) {
+		if (repo != NULL && assign->value == git_attr__true) {
 			git_attr_rule *macro =
 				git_attr_cache__lookup_macro(repo, assign->name);
 
diff --git a/src/attr_file.h b/src/attr_file.h
index 7939f83..9d6730d 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -24,6 +24,10 @@
 #define GIT_ATTR_FNMATCH_HASWILD	(1U << 5)
 #define GIT_ATTR_FNMATCH_ALLOWSPACE	(1U << 6)
 
+extern const char *git_attr__true;
+extern const char *git_attr__false;
+extern const char *git_attr__unset;
+
 typedef struct {
 	char *pattern;
 	size_t length;