Commit f83ef56209d9219ea80a142551202862df897426

Vicent Marti 2014-02-21T01:33:47

Merge pull request #2129 from arrbee/rb/c89-or-c99 Improve C89 compatibility and clarify use of C99 features

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 807cd53..06aa4c1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -5,9 +5,13 @@ your help.
 
 ## Licensing
 
-By contributing to libgit2, you agree to release your contribution under the terms of the license.
-For code under `examples`, this is governed by the [CC0 Public Domain Dedication](examples/COPYING).
-All other code is released under the [GPL v2 with linking exception](COPYING).
+By contributing to libgit2, you agree to release your contribution under
+the terms of the license.  Except for the `examples` directory, all code
+is released under the [GPL v2 with linking exception](COPYING).
+
+The `examples` code is governed by the
+[CC0 Public Domain Dedication](examples/COPYING), so that you may copy
+from them into your own application.
 
 ## Discussion & Chat
 
@@ -76,15 +80,19 @@ you're porting code *from* to see what you need to do.  As a general rule,
 MIT and BSD (3-clause) licenses are typically no problem.  Apache 2.0
 license typically doesn't work due to GPL incompatibility.
 
-If you are pulling in code from core Git, another project or code you've pulled from
-a forum / Stack Overflow then please flag this in your PR and also make sure you've
-given proper credit to the original author in the code snippet.
+If you are pulling in code from core Git, another project or code you've
+pulled from a forum / Stack Overflow then please flag this in your PR and
+also make sure you've given proper credit to the original author in the
+code snippet.
 
 ## Style Guide
 
-`libgit2` is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
-(a.k.a. C89) with some specific conventions for function and type naming,
-code formatting, and testing.
+The public API of `libgit2` is [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
+(a.k.a. C89) compatible.  Internally, `libgit2` is written using a portable
+subset of C99 - in order to compile with GCC, Clang, MSVC, etc., we keep
+local variable declarations at the tops of blocks only and avoid `//` style
+comments.  Additionally, `libgit2` follows some extra conventions for
+function and type naming, code formatting, and testing.
 
 We like to keep the source code consistent and easy to read.  Maintaining
 this takes some discipline, but it's been more than worth it.  Take a look
@@ -101,14 +109,15 @@ are any unresolved issues to jump in on.  Also, here is a list of some
 smaller project ideas that could help you become familiar with the code
 base and make a nice first step:
 
-* Convert a `git_*modulename*_foreach()` callback-based iteration API
-  into a `git_*modulename*_iterator` object with a create/advance style
-  of API.  This helps folks writing language bindings and usually isn't
-  too complicated.
-* Write a new `examples/` program that mirrors a particular core git
-  command.  (See `examples/diff.c` for example.)  This lets you (and us)
-  easily exercise a particular facet of the API and measure compatability
-  and feature parity with core git.
+* Look at the `examples/` programs, find an existing one that mirrors a
+  core Git command and add a missing command-line option.  There are many
+  gaps right now and this helps demonstrate how to use the library.
+* Pick a Git command that is not emulates in `examples/` and write a new
+  example that mirrors the behavior.  Examples don't have to be perfect
+  emulations, but should demonstrate how to use the libgit2 APIs to get
+  results that are similar to Git commands.  This lets you (and us) easily
+  exercise a particular facet of the API and measure compatability and
+  feature parity with core git.
 * Submit a PR to clarify documentation! While we do try to document all of
   the APIs, your fresh eyes on the documentation will find areas that are
   confusing much more easily.
diff --git a/CONVENTIONS.md b/CONVENTIONS.md
index 59b41a2..5b8238a 100644
--- a/CONVENTIONS.md
+++ b/CONVENTIONS.md
@@ -6,14 +6,18 @@ guidelines that should help with that.
 ## Compatibility
 
 `libgit2` runs on many different platforms with many different compilers.
-It is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C) (a.k.a. C89)
-with some specific standards for function and type naming, code formatting,
-and testing.
 
-We try to avoid more recent extensions to maximize portability.  We also, to
-the greatest extent possible, try to avoid lots of `#ifdef`s inside the core
-code base.  This is somewhat unavoidable, but since it can really hamper
-maintainability, we keep it to a minimum.
+The public API of `libgit2` is [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
+(a.k.a. C89) compatible.
+
+Internally, `libgit2` is written using a portable subset of C99 - in order
+to maximize compatibility (e.g. with MSVC) we avoid certain C99
+extensions.  Specifically, we keep local variable declarations at the tops
+of blocks only and we avoid `//` style comments.
+
+Also, to the greatest extent possible, we try to avoid lots of `#ifdef`s
+inside the core code base.  This is somewhat unavoidable, but since it can
+really hamper maintainability, we keep it to a minimum.
 
 ## Match Surrounding Code
 
@@ -209,6 +213,9 @@ All inlined functions must be declared as:
 GIT_INLINE(result_type) git_modulename_functionname(arg_list);
 ```
 
+`GIT_INLINE` (or `inline`) should not be used in public headers in order
+to preserve ANSI C compatibility.
+
 ## Tests
 
 `libgit2` uses the [clar](https://github.com/vmg/clar) testing framework.
diff --git a/README.md b/README.md
index f814b87..aa75bb0 100644
--- a/README.md
+++ b/README.md
@@ -20,17 +20,17 @@ Additionally, the example code has been released to the public domain (see the
 * API documentation: <http://libgit2.github.com/libgit2>
 * IRC: [#libgit2](irc://irc.freenode.net/libgit2) on irc.freenode.net.
 * Mailing list: The libgit2 mailing list was
-    traditionally hosted in Librelist but has been deprecated. We encourage you to 
+    traditionally hosted in Librelist but has been deprecated. We encourage you to
     [use StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) instead for any questions regarding
-    the library, or [open an issue](https://github.com/libgit2/libgit2/issues) 
-    on GitHub for bug reports.  The mailing list archives are still available at 
+    the library, or [open an issue](https://github.com/libgit2/libgit2/issues)
+    on GitHub for bug reports.  The mailing list archives are still available at
     <http://librelist.com/browser/libgit2/>.
 
 
 What It Can Do
 ==============
 
-`libgit2` is already very usable and is being used in production for many applications including the GitHub.com site, in Plastic SCM 
+`libgit2` is already very usable and is being used in production for many applications including the GitHub.com site, in Plastic SCM
 and also powering Microsoft's Visual Studio tools for Git.  The library provides:
 
 * SHA conversions, formatting and shortening
@@ -65,7 +65,7 @@ Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthrea
 they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
 for threading.
 
-The `libgit2` library is built using `CMake 2.6+` (<http://www.cmake.org>) on all platforms.
+The `libgit2` library is built using [CMake](<http://www.cmake.org>) (version 2.6 or newer) on all platforms.
 
 On most systems you can build the library using the following commands
 
diff --git a/include/git2/common.h b/include/git2/common.h
index dca0c9c..4927154 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -37,13 +37,6 @@
 # define GIT_EXTERN(type) extern type
 #endif
 
-/** Declare a function as always inlined. */
-#if defined(_MSC_VER)
-# define GIT_INLINE(type) static __inline type
-#else
-# define GIT_INLINE(type) static inline type
-#endif
-
 /** Declare a function's takes printf style arguments. */
 #ifdef __GNUC__
 # define GIT_FORMAT_PRINTF(a,b) __attribute__((format (printf, a, b)))
diff --git a/include/git2/index.h b/include/git2/index.h
index 4363a3b..ae919e1 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -120,10 +120,10 @@ typedef struct git_index_entry {
 
 /** Capabilities of system that affect index actions. */
 typedef enum {
-	GIT_INDEXCAP_IGNORE_CASE = 1u,
-	GIT_INDEXCAP_NO_FILEMODE = 2u,
-	GIT_INDEXCAP_NO_SYMLINKS = 4u,
-	GIT_INDEXCAP_FROM_OWNER  = ~0u
+	GIT_INDEXCAP_IGNORE_CASE = 1,
+	GIT_INDEXCAP_NO_FILEMODE = 2,
+	GIT_INDEXCAP_NO_SYMLINKS = 4,
+	GIT_INDEXCAP_FROM_OWNER  = -1,
 } git_indexcap_t;
 
 /** Callback for APIs that add/remove/update files matching pathspec */
@@ -206,7 +206,7 @@ GIT_EXTERN(git_repository *) git_index_owner(const git_index *index);
  * @param index An existing index object
  * @return A combination of GIT_INDEXCAP values
  */
-GIT_EXTERN(unsigned int) git_index_caps(const git_index *index);
+GIT_EXTERN(int) git_index_caps(const git_index *index);
 
 /**
  * Set index capabilities flags.
@@ -219,7 +219,7 @@ GIT_EXTERN(unsigned int) git_index_caps(const git_index *index);
  * @param caps A combination of GIT_INDEXCAP values
  * @return 0 on success, -1 on failure
  */
-GIT_EXTERN(int) git_index_set_caps(git_index *index, unsigned int caps);
+GIT_EXTERN(int) git_index_set_caps(git_index *index, int caps);
 
 /**
  * Update the contents of an existing index object in memory by reading
diff --git a/include/git2/oid.h b/include/git2/oid.h
index 384b656..1cfd4e5 100644
--- a/include/git2/oid.h
+++ b/include/git2/oid.h
@@ -167,10 +167,7 @@ GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b);
  * @param b second oid structure.
  * @return true if equal, false otherwise
  */
-GIT_INLINE(int) git_oid_equal(const git_oid *a, const git_oid *b)
-{
-	return !git_oid_cmp(a, b);
-}
+GIT_EXTERN(int) git_oid_equal(const git_oid *a, const git_oid *b);
 
 /**
  * Compare the first 'len' hexadecimal characters (packets of 4 bits)
diff --git a/src/array.h b/src/array.h
index 1d4e1c2..f8a4872 100644
--- a/src/array.h
+++ b/src/array.h
@@ -7,7 +7,7 @@
 #ifndef INCLUDE_array_h__
 #define INCLUDE_array_h__
 
-#include "util.h"
+#include "common.h"
 
 /*
  * Use this to declare a typesafe resizable array of items, a la:
diff --git a/src/bitvec.h b/src/bitvec.h
index fd6f0cc..544832d 100644
--- a/src/bitvec.h
+++ b/src/bitvec.h
@@ -7,7 +7,7 @@
 #ifndef INCLUDE_bitvec_h__
 #define INCLUDE_bitvec_h__
 
-#include "util.h"
+#include "common.h"
 
 /*
  * This is a silly little fixed length bit vector type that will store
diff --git a/src/common.h b/src/common.h
index e315b59..d389cf8 100644
--- a/src/common.h
+++ b/src/common.h
@@ -10,6 +10,13 @@
 #include "git2/common.h"
 #include "cc-compat.h"
 
+/** Declare a function as always inlined. */
+#if defined(_MSC_VER)
+# define GIT_INLINE(type) static __inline type
+#else
+# define GIT_INLINE(type) static inline type
+#endif
+
 #include <assert.h>
 #include <errno.h>
 #include <limits.h>
diff --git a/src/index.c b/src/index.c
index aa1aebf..e0c0022 100644
--- a/src/index.c
+++ b/src/index.c
@@ -438,7 +438,7 @@ static int create_index_error(int error, const char *msg)
 	return error;
 }
 
-int git_index_set_caps(git_index *index, unsigned int caps)
+int git_index_set_caps(git_index *index, int caps)
 {
 	unsigned int old_ignore_case;
 
@@ -474,7 +474,7 @@ int git_index_set_caps(git_index *index, unsigned int caps)
 	return 0;
 }
 
-unsigned int git_index_caps(const git_index *index)
+int git_index_caps(const git_index *index)
 {
 	return ((index->ignore_case ? GIT_INDEXCAP_IGNORE_CASE : 0) |
 			(index->distrust_filemode ? GIT_INDEXCAP_NO_FILEMODE : 0) |
diff --git a/src/merge.c b/src/merge.c
index 97c1479..12ff1c9 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -2364,7 +2364,7 @@ done:
 int git_merge__indexes(git_repository *repo, git_index *index_new)
 {
 	git_index *index_repo = NULL;
-	unsigned int index_repo_caps = 0;
+	int index_repo_caps = 0;
 	git_vector paths = GIT_VECTOR_INIT;
 	size_t index_conflicts = 0, wd_conflicts = 0, conflicts, i;
 	char *path;
diff --git a/src/oid.c b/src/oid.c
index 567b6cf..f74c43f 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -179,6 +179,11 @@ int git_oid_cmp(const git_oid *a, const git_oid *b)
 	return git_oid__cmp(a, b);
 }
 
+int git_oid_equal(const git_oid *a, const git_oid *b)
+{
+	return (git_oid__cmp(a, b) == 0);
+}
+
 int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len)
 {
 	const unsigned char *a = oid_a->id;
diff --git a/src/vector.h b/src/vector.h
index f825685..682b6ad 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -7,7 +7,7 @@
 #ifndef INCLUDE_vector_h__
 #define INCLUDE_vector_h__
 
-#include "git2/common.h"
+#include "common.h"
 
 typedef int (*git_vector_cmp)(const void *, const void *);
 
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index 56b5185..fb70a9e 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -156,7 +156,7 @@ void test_repo_iterator__index_icase(void)
 {
 	git_iterator *i;
 	git_index *index;
-	unsigned int caps;
+	int caps;
 
 	g_repo = cl_git_sandbox_init("icase");