1 #include "emacs-module.h" 2 #include "git2.h" 3 #include "git2.h" 4 5 #ifndef EGIT_H 6 #define EGIT_H 7 8 /** 9 * Macro that defines a docstring for a function. 10 * @param name The function name (without egit_ prefix). 11 * @param args The argument list as visible from Emacs (without parens). 12 * @param docstring The rest of the documentation. 13 */ 14 #define EGIT_DOC(name, args, docstring) \ 15 const char *egit_##name##__doc = (docstring "\n\n(fn " args ")") 16 17 /** 18 * Macro that declares a function and its docstring variable. 19 * @param name The function name (without egit_ prefix) 20 * @param ... The function arguments (without emacs_env) 21 */ 22 #define EGIT_DEFUN(name, ...) \ 23 extern const char *egit_##name##__doc; \ 24 emacs_value egit_##name(emacs_env *env, __VA_ARGS__) 25 26 // Variant of EGIT_DEFUN for zero parameters. 27 #define EGIT_DEFUN_0(name) \ 28 extern const char *egit_##name##__doc; \ 29 emacs_value egit_##name(emacs_env *env) 30 31 // Assert that VAL is a git annotated commit, signal an error and return otherwise. 32 #define EGIT_ASSERT_ANNOTATED_COMMIT(val) \ 33 do { if (!egit_assert_type(env, (val), EGIT_ANNOTATED_COMMIT, esym_libgit_annotated_commit_p)) return esym_nil; } while (0) 34 35 // Assert that VAL is a git blame, signal an error and return otherwise. 36 #define EGIT_ASSERT_BLAME(val) \ 37 do { if (!egit_assert_type(env, (val), EGIT_BLAME, esym_libgit_blame_p)) return esym_nil; } while (0) 38 39 // Assert that VAL is a git blob, signal an error and return otherwise. 40 #define EGIT_ASSERT_BLOB(val) \ 41 do { if (!egit_assert_type(env, (val), EGIT_BLOB, esym_libgit_blob_p)) return esym_nil; } while (0) 42 43 // Assert that VAL is a git blame hunk, signal an error and return otherwise. 44 #define EGIT_ASSERT_BLAME_HUNK(val) \ 45 do { if (!egit_assert_type(env, (val), EGIT_BLAME_HUNK, esym_libgit_blame_hunk_p)) return esym_nil; } while (0) 46 47 // Assert that VAL is a git commit, signal an error and return otherwise. 48 #define EGIT_ASSERT_COMMIT(val) \ 49 do { if (!egit_assert_type(env, (val), EGIT_COMMIT, esym_libgit_commit_p)) return esym_nil; } while (0) 50 51 // Assert that VAL is a git config, signal an error and return otherwise. 52 #define EGIT_ASSERT_CONFIG(val) \ 53 do { if (!egit_assert_type(env, (val), EGIT_CONFIG, esym_libgit_config_p)) return esym_nil; } while (0) 54 55 // Assert that VAL is a git credential, signal an error and return otherwise. 56 #define EGIT_ASSERT_CRED(val) \ 57 do { if (!egit_assert_type(env, (val), EGIT_CRED, esym_libgit_cred_p)) return esym_nil; } while (0) 58 59 // Assert that VAL is a git diff, signal an error and return otherwise. 60 #define EGIT_ASSERT_DIFF(val) \ 61 do { if (!egit_assert_type(env, (val), EGIT_DIFF, esym_libgit_diff_p)) return esym_nil; } while (0) 62 63 // Assert that VAL is a git diff delta, signal an error and return otherwise. 64 #define EGIT_ASSERT_DIFF_DELTA(val) \ 65 do { if (!egit_assert_type(env, (val), EGIT_DIFF_DELTA, esym_libgit_diff_delta_p)) return esym_nil; } while (0) 66 67 // Assert that VAL is a git diff binary, signal an error and return otherwise. 68 #define EGIT_ASSERT_DIFF_BINARY(val) \ 69 do { if (!egit_assert_type(env, (val), EGIT_DIFF_BINARY, esym_libgit_diff_binary_p)) return esym_nil; } while (0) 70 71 // Assert that VAL is a git diff hunk, signal an error and return otherwise. 72 #define EGIT_ASSERT_DIFF_HUNK(val) \ 73 do { if (!egit_assert_type(env, (val), EGIT_DIFF_HUNK, esym_libgit_diff_hunk_p)) return esym_nil; } while (0) 74 75 // Assert that VAL is a git diff line, signal an error and return otherwise. 76 #define EGIT_ASSERT_DIFF_LINE(val) \ 77 do { if (!egit_assert_type(env, (val), EGIT_DIFF_LINE, esym_libgit_diff_line_p)) return esym_nil; } while (0) 78 79 // Assert that VAL is a git index, signal an error and return otherwise. 80 #define EGIT_ASSERT_INDEX(val) \ 81 do { if (!egit_assert_type(env, (val), EGIT_INDEX, esym_libgit_index_p)) return esym_nil; } while (0) 82 83 // Assert that VAL is a git index entry, signal an error and return otherwise. 84 #define EGIT_ASSERT_INDEX_ENTRY(val) \ 85 do { if (!egit_assert_type(env, (val), EGIT_INDEX_ENTRY, esym_libgit_index_entry_p)) return esym_nil; } while (0) 86 87 // Assert that VAL is a git object, signal an error and return otherwise. 88 #define EGIT_ASSERT_OBJECT(val) \ 89 do { if (!egit_assert_object(env, (val))) return esym_nil; } while (0) 90 91 // Assert that VAL is a git pathspec, signal an error and return otherwise. 92 #define EGIT_ASSERT_PATHSPEC(val) \ 93 do { if (!egit_assert_type(env, (val), EGIT_PATHSPEC, esym_libgit_pathspec_p)) return esym_nil; } while (0) 94 95 // Assert that VAL is a git pathspec match list, signal an error and return otherwise. 96 #define EGIT_ASSERT_PATHSPEC_MATCH_LIST(val) \ 97 do { if (!egit_assert_type(env, (val), EGIT_PATHSPEC_MATCH_LIST, esym_libgit_pathspec_match_list_p)) return esym_nil; } while (0) 98 99 // Assert that VAL is a git reference, signal an error and return otherwise. 100 #define EGIT_ASSERT_REFERENCE(val) \ 101 do { if (!egit_assert_type(env, (val), EGIT_REFERENCE, esym_libgit_reference_p)) return esym_nil; } while (0) 102 103 // Assert that VAL is a reflog, signal an error and return otherwise. 104 #define EGIT_ASSERT_REFLOG(val) \ 105 do { if (!egit_assert_type(env, (val), EGIT_REFLOG, esym_libgit_reflog_p)) return esym_nil; } while (0) 106 107 // Assert that VAL is a reflog entry, signal an error and return otherwise. 108 #define EGIT_ASSERT_REFLOG_ENTRY(val) \ 109 do { if (!egit_assert_type(env, (val), EGIT_REFLOG_ENTRY, esym_libgit_reflog_entry_p)) return esym_nil; } while (0) 110 111 // Assert that VAL is a git refspec, signal an error and return otherwise. 112 #define EGIT_ASSERT_REFSPEC(val) \ 113 do { if (!egit_assert_type(env, (val), EGIT_REFSPEC, esym_libgit_refspec_p)) return esym_nil; } while (0) 114 115 // Assert that VAL is a git remote, signal an error and return otherwise. 116 #define EGIT_ASSERT_REMOTE(val) \ 117 do { if (!egit_assert_type(env, (val), EGIT_REMOTE, esym_libgit_remote_p)) return esym_nil; } while (0) 118 119 // Assert that VAL is a git repository, signal an error and return otherwise. 120 #define EGIT_ASSERT_REPOSITORY(val) \ 121 do { if (!egit_assert_type(env, (val), EGIT_REPOSITORY, esym_libgit_repository_p)) return esym_nil; } while (0) 122 123 // Assert that VAL is a git revwalk, signal an error and return otherwise. 124 #define EGIT_ASSERT_REVWALK(val) \ 125 do { if (!egit_assert_type(env, (val), EGIT_REVWALK, esym_libgit_revwalk_p)) return esym_nil; } while (0) 126 127 // Assert that VAL is a signature, signal an error and return otherwise. 128 #define EGIT_ASSERT_SIGNATURE(val) \ 129 do { if (!egit_assert_type(env, (val), EGIT_SIGNATURE, esym_libgit_signature_p)) return esym_nil; } while (0) 130 131 // Assert that VAL is a transaction, signal an error and return otherwise. 132 #define EGIT_ASSERT_SIGNATURE_OR_NIL(val) \ 133 do { if (EGIT_EXTRACT_BOOLEAN(val)) EGIT_ASSERT_SIGNATURE(val); } while (0) 134 135 // Assert that VAL is a signature, signal an error and return otherwise. 136 #define EGIT_ASSERT_SUBMODULE(val) \ 137 do { if (!egit_assert_type(env, (val), EGIT_SUBMODULE, esym_libgit_submodule_p)) return esym_nil; } while (0) 138 139 // Assert that VAL is a transaction, signal an error and return otherwise. 140 #define EGIT_ASSERT_TAG(val) \ 141 do { if (!egit_assert_type(env, (val), EGIT_TAG, esym_libgit_tag_p)) return esym_nil; } while (0) 142 143 // Assert that VAL is a transaction, signal an error and return otherwise. 144 #define EGIT_ASSERT_TRANSACTION(val) \ 145 do { if (!egit_assert_type(env, (val), EGIT_TRANSACTION, esym_libgit_transaction_p)) return esym_nil; } while (0) 146 147 // Assert that VAL is a tree, signal an error and return otherwise. 148 #define EGIT_ASSERT_TREE(val) \ 149 do { if (!egit_assert_type(env, (val), EGIT_TREE, esym_libgit_tree_p)) return esym_nil; } while (0) 150 151 // Assert that VAL is a treebuilder, signal an error and return otherwise. 152 #define EGIT_ASSERT_TREEBUILDER(val) \ 153 do { if (!egit_assert_type(env, (val), EGIT_TREEBUILDER, esym_libgit_treebuilder_p)) return esym_nil; } while (0) 154 155 /** 156 * Extract a libgit git_??? struct from an emacs_value. 157 * Caller is responsible for ensuring that this is a valid operation. 158 */ 159 #define EGIT_EXTRACT(val) (((egit_object*) EM_EXTRACT_USER_PTR(val))->ptr) 160 161 /** 162 * Extract a libgit git_??? struct from an emacs_value, or NULL. 163 * Caller is responsible for ensuring that this is a valid operation. 164 */ 165 #define EGIT_EXTRACT_OR_NULL(val) \ 166 (EM_EXTRACT_BOOLEAN(val) ? EGIT_EXTRACT(val) : NULL); 167 168 /** 169 * Extract egit_object pointer representing a parent object, or NULL. 170 * Caller is responsible for ensuring that this is a valid operation. 171 */ 172 #define EGIT_EXTRACT_PARENT(val) \ 173 (((egit_object*) EM_EXTRACT_USER_PTR(val))->parent) \ 174 175 /** 176 * Extract a git_oid from an emacs_value. 177 * Caller is responsible for ensuring that the emacs_value is a string. 178 */ 179 #define EGIT_EXTRACT_OID(val, tgt) \ 180 do { \ 181 char *__str = em_get_string(env, (val)); \ 182 int __retval = git_oid_fromstrp(&(tgt), __str); \ 183 free(__str); \ 184 EGIT_CHECK_ERROR(__retval); \ 185 } while (0) 186 187 /** 188 * Extract a partial git_oid from an emacs_value and store its length. 189 * Caller is responsible for ensuring that the emacs_value is a string. 190 */ 191 #define EGIT_EXTRACT_OID_PREFIX(val, tgt, tgt_len) \ 192 do { \ 193 char *__str = em_get_string(env, (val)); \ 194 tgt_len = strlen(__str); \ 195 int __retval = git_oid_fromstrp(&(tgt), __str); \ 196 free(__str); \ 197 EGIT_CHECK_ERROR(__retval); \ 198 } while (0) 199 200 /** 201 * If libgit2 signalled an error, pass the error on to Emacs and return. 202 * @param val A libgit2 return value (negative value indicates error). 203 */ 204 #define EGIT_CHECK_ERROR(val) \ 205 do { if (egit_dispatch_error(env, (val))) return esym_nil; } while (0) 206 207 /** 208 * Convert a git_buf to an Emacs string and return it, freeing the git_buf in the process. 209 */ 210 #define EGIT_RET_BUF_AS_STRING(buf) \ 211 do { \ 212 emacs_value ret = env->make_string(env, (buf).ptr, (buf).size); \ 213 git_buf_dispose(&(buf)); \ 214 return ret; \ 215 } while (0) 216 217 /** 218 * Convert a git_strarray to an Emacs list and return it, freeing the git_strarray in the process. 219 */ 220 #define EGIT_RET_STRARRAY(arr) \ 221 do { \ 222 emacs_value list = esym_nil; \ 223 for (ptrdiff_t c = (arr).count-1; c >= 0; c--) { \ 224 emacs_value str = EM_STRING((arr).strings[c]); \ 225 list = em_cons(env, str, list); \ 226 } \ 227 git_strarray_free(&(arr)); \ 228 return list; \ 229 } while (0) 230 231 /** 232 * Set or unset a bit according to the truth value of an emacs value. 233 * @param tgt The value to change 234 * @param bit The bit to flip 235 * @param opt The determining emacs value 236 */ 237 #define EGIT_SET_BIT(tgt, bit, opt) \ 238 do { \ 239 if (EM_EXTRACT_BOOLEAN(opt)) \ 240 (tgt) |= (bit); \ 241 else \ 242 (tgt) &= ~(bit); \ 243 } while (0) 244 245 /** 246 * Enum used to distinguish between various types of git_??? structs. 247 */ 248 typedef enum { 249 EGIT_UNKNOWN, 250 EGIT_REPOSITORY, 251 EGIT_REFERENCE, 252 EGIT_COMMIT, 253 EGIT_TREE, 254 EGIT_BLOB, 255 EGIT_TAG, 256 EGIT_OBJECT, 257 EGIT_SIGNATURE, 258 EGIT_BLAME, 259 EGIT_BLAME_HUNK, 260 EGIT_CONFIG, 261 EGIT_TRANSACTION, 262 EGIT_INDEX, 263 EGIT_INDEX_ENTRY, 264 EGIT_DIFF, 265 EGIT_DIFF_DELTA, 266 EGIT_DIFF_BINARY, 267 EGIT_DIFF_HUNK, 268 EGIT_DIFF_LINE, 269 EGIT_PATHSPEC, 270 EGIT_PATHSPEC_MATCH_LIST, 271 EGIT_REMOTE, 272 EGIT_REFSPEC, 273 EGIT_SUBMODULE, 274 EGIT_CRED, 275 EGIT_ANNOTATED_COMMIT, 276 EGIT_REFLOG, 277 EGIT_REFLOG_ENTRY, 278 EGIT_REVWALK, 279 EGIT_TREEBUILDER 280 } egit_type; 281 282 /** 283 * Hashable wrapper structure for a git_??? struct. 284 * These are used in an internal object hash-table to ensure that pointers aren't freed too early. 285 * This is necessary since there may be many emacs_values that point to the same git_repository 286 * (for example), so we can't just free the git_repository pointer in a finalizer called from Emacs. 287 * Moreover, emacs_values that store e.g. git_object pointers must keep the git_repository alive. 288 * To fix this we keep a hash table of pointers mapping to egit_objects, counting references and 289 * freeing objects when they reach zero. 290 * 291 * User-pointers returned to Emacs should always wrap a struct of type egit_object. 292 */ 293 typedef struct egit_object_s egit_object; 294 295 struct egit_object_s { 296 egit_type type; /**< Type of object stored. */ 297 ptrdiff_t refcount; /**< Reference count. */ 298 void *ptr; /**< Pointer to git_??? structure. */ 299 egit_object *parent; /**< Optional pointer to parent wrapper. */ 300 }; 301 302 /** 303 * Return the git object type stored by en Emacs value. 304 * @param env The active Emacs environment. 305 * @param _obj The value to check. 306 * @return The object type, or EGIT_UNKNOWN if not known. 307 */ 308 egit_type egit_get_type(emacs_env *env, emacs_value _obj); 309 310 /** 311 * Assert that an Emacs value represents a libgit2 struct of a given type, or signal an Emacs error. 312 * To check for EGIT_OBJECT, use egit_assert_object instead. 313 * @param env The active Emacs environment. 314 * @param obj The value to check. 315 * @param type The type to check for. 316 * @param predicate Symbol to use in a wrong-type-argument error signal. 317 * @return True iff the value has the right type. 318 */ 319 bool egit_assert_type(emacs_env *env, emacs_value obj, egit_type type, emacs_value predicate); 320 321 /** 322 * Assert that an Emacs value represents a libgit2 git_object struct, or signal an Emacs error. 323 * @param env The active Emacs environment. 324 * @param obj The value to check. 325 * @return True iff the value has the right type. 326 */ 327 bool egit_assert_object(emacs_env *env, emacs_value obj); 328 329 /** 330 * Signal a wrong-type-argument error if ARG is not a proper list, every 331 * element of which satisfies has the correct libgit2 type. 332 * @param env The active Emacs environment. 333 * @param type The type to check for. 334 * @param predicate Symbol to use in a wrong-type-argument error signal. 335 * @param arg The list. 336 * @return The number of elements in the list, or negative if error. 337 */ 338 ptrdiff_t egit_assert_list(emacs_env *env, egit_type type, emacs_value predicate, emacs_value arg); 339 340 /** 341 * Finalizer for user pointers. 342 */ 343 void egit_finalize(void* _obj); 344 345 /** 346 * Wrap a git_??? structure in an emacs_value. 347 * @param env The active Emacs environment. 348 * @param obj The type of the object. 349 * @param ptr The pointer to store. 350 * @return The Emacs value. 351 */ 352 emacs_value egit_wrap(emacs_env *env, egit_type type, const void* ptr, egit_object *parent); 353 354 /** 355 * If libgit2 signaled an error, dispatch that error to Emacs. 356 * @param env The active Emacs environment. 357 * @param retval A libgit2 return value. 358 * @return True iff an error was signalled. 359 */ 360 bool egit_dispatch_error(emacs_env *env, int retval); 361 362 /** 363 * Define functions visible to Emacs. 364 * This function only needs to be called once. 365 * @param env The active Emacs environment. 366 */ 367 void egit_init(emacs_env *env); 368 369 #endif /* EGIT_H */ 370