1 #include <stdarg.h>
2 #include <string.h>
3 
4 #include "emacs-module.h"
5 #include "symbols.h"
6 
7 #ifndef INTERFACE_H
8 #define INTERFACE_H
9 
10 // Assert that VAL is a cons cell, signal an error and return otherwise.
11 #define EM_ASSERT_CONS(val)                                             \
12     do { if (!em_assert(env, esym_consp, (val))) return esym_nil; } while (0)
13 
14 // Assert that VAL is a function, signal an error and return otherwise.
15 #define EM_ASSERT_FUNCTION(val)                                         \
16     do { if (!em_assert(env, esym_functionp, (val))) return esym_nil; } while (0)
17 
18 // Assert that VAL is a string, signal an error and return otherwise.
19 #define EM_ASSERT_STRING(val)                                           \
20     do { if (!em_assert(env, esym_stringp, (val))) return esym_nil; } while (0)
21 
22 // Assert that VAL is a string or nil, signal an error and return otherwise.
23 #define EM_ASSERT_STRING_OR_NIL(val)                                    \
24     do { if (EM_EXTRACT_BOOLEAN(val)) EM_ASSERT_STRING(val); } while (0)
25 
26 // Assert that VAL is an integer, signal an error and return otherwise.
27 #define EM_ASSERT_INTEGER(val)                                          \
28     do { if (!em_assert(env, esym_integerp, (val))) return esym_nil; } while (0)
29 
30 // Assert that VAL is an integer or nil, signal an error and return otherwise.
31 #define EM_ASSERT_INTEGER_OR_NIL(val)                                   \
32     do { if (EM_EXTRACT_BOOLEAN(val)) EM_ASSERT_INTEGER(val); } while (0)
33 
34 // Assert that VAL is an user-ptr, signal an error and return otherwise.
35 #define EM_ASSERT_USER_PTR(val)                                         \
36     do { if (!em_assert(env, esym_user_ptrp, (val))) return esym_nil; } while (0)
37 
38 // Normalize an emacs_value string path. This macro may return.
39 #define EM_NORMALIZE_PATH(val)                                  \
40     do {                                                        \
41         (val) = em_expand_file_name(env, val);                  \
42         EM_RETURN_NIL_IF_NLE();                                 \
43     } while (0)
44 
45 // Extract a boolean from an emacs_value.
46 #define EM_EXTRACT_BOOLEAN(val) (env->is_not_nil(env, (val)) ? 1 : 0)
47 
48 // Extract a string from an emacs_value.
49 // Caller is responsible for ensuring that the emacs_value represents a string.
50 #define EM_EXTRACT_STRING(val) em_get_string(env, (val));
51 
52 // Extract an integer from an emacs_value.
53 // Caller is responsible for ensuring that the emacs_value represents an integer.
54 #define EM_EXTRACT_INTEGER(val) env->extract_integer(env, (val))
55 
56 // Extract an integer from an emacs_value with a default.
57 // Caller is responsible for ensuring that the emacs_value represents an integer or nil.
58 #define EM_EXTRACT_INTEGER_OR_DEFAULT(val, default)                     \
59     (EM_EXTRACT_BOOLEAN(val) ? EM_EXTRACT_INTEGER(val) : (default))
60 
61 // Extract a string from an emacs_value, or NULL.
62 // Caller is responsible for ensuring that the emacs_value represents a string or nil.
63 #define EM_EXTRACT_STRING_OR_NULL(val)                                  \
64     (EM_EXTRACT_BOOLEAN(val) ? em_get_string(env, (val)) : NULL)
65 
66 // Extract a user pointer from an emacs_value.
67 // Caller is responsible for ensuring that the emacs_value represents a user pointer.
68 #define EM_EXTRACT_USER_PTR(val) env->get_user_ptr(env, (val))
69 
70 // Call (eq a b) in Emacs
71 #define EM_EQ(a,b) (env->eq(env, (a), (b)))
72 
73 // Create an Emacs integer
74 #define EM_INTEGER(val) (env->make_integer(env, (val)))
75 
76 // Create an Emacs string from a null-terminated char*
77 #define EM_STRING(val) (env->make_string(env, (val), strlen(val)))
78 
79 // Create an Emacs user pointer
80 #define EM_USER_PTR(val, fin) (env->make_user_ptr(env, (fin), (val)))
81 
82 // Return if a non-local exit is set
83 #define EM_RETURN_IF_NLE(val)                    \
84     do {                                         \
85         if (env->non_local_exit_check(env))      \
86             return (val);                        \
87     } while (0)
88 
89 #define EM_RETURN_NIL_IF_NLE() EM_RETURN_IF_NLE(esym_nil)
90 
91 /**
92  * Initiate a loop over an Emacs list.
93  * If any element is not a cons cell or nil, it WILL signal an error and return nil.
94  * @param var Variable bound to each car.
95  * @param listvar List to loop over.
96  * @param name Unique name identifying the loop.
97  */
98 #define EM_DOLIST(var, listvar, name)                               \
99     emacs_value __cell##name = (listvar);                           \
100     __loop##name:                                                   \
101     if (!EM_EXTRACT_BOOLEAN(__cell##name)) goto __end##name;        \
102     if (!em_assert(env, esym_consp, __cell##name)) return esym_nil;    \
103     emacs_value (var) = em_car(env, __cell##name)
104 
105 /**
106  * Close a loop over an Emacs lisp.
107  * @param name: Unique name identifying the loop.
108  */
109 #define EM_DOLIST_END(name)                     \
110     __cell##name = em_cdr(env, __cell##name);   \
111     goto __loop##name;                          \
112     __end##name:
113 
114 /**
115  * Initialize the libegit2-emacs interface.
116  * This function should only be called once.
117  */
118 void em_init(emacs_env *env);
119 
120 /**
121  * Signal a wrong-type-argument error if PREDICATE does not apply to ARG.
122  * @param env The active Emacs environment.
123  * @param predicate The predicate.
124  * @param arg The argument.
125  * @return True iff an error was signaled.
126  */
127 bool em_assert(emacs_env *env, emacs_value predicate, emacs_value arg);
128 
129 /**
130  * Signal a wrong-type-argument error if ARG is not a proper list, every
131  * element of which satisfies PREDICATE. PREDICATE may be nil, in which
132  * case only the list-ness is checked.
133  * @param env The active Emacs environment.
134  * @param predicate The predicate.
135  * @param arg The list.
136  * @return The number of elements in the list, or negative if error.
137  */
138 ptrdiff_t em_assert_list(emacs_env *env, emacs_value predicate, emacs_value arg);
139 
140 /**
141  * Signal an error with string message.
142  * @param env The active Emacs environment.
143  * @param error The error symbol.
144  * @param _msg The error message.
145  */
146 void em_signal(emacs_env *env, emacs_value error, const char* _msg);
147 
148 /**
149  * Signal a wrong-type-argument error.
150  * @param env The active Emacs environment.
151  * @param expected Symbol describing the expected type.
152  * @param actual Emacs value that does not have the expected type.
153  */
154 void em_signal_wrong_type(emacs_env *env, emacs_value expected, emacs_value actual);
155 
156 /**
157  * Signal a wrong-value-argument error.
158  * @param env The active Emacs environment.
159  * @param actual Emacs value that does not have the expected value.
160  */
161 void em_signal_wrong_value(emacs_env *env, emacs_value actual);
162 
163 /**
164  * Signal an args-out-of-range error.
165  * @param env The active Emacs environment.
166  * @param index The erroneous index.
167  */
168 void em_signal_args_out_of_range(emacs_env *env, intmax_t index);
169 
170 /**
171  * Return a string with size from an emacs_value.
172  * Caller is responsible for ensuring that the value is a string, and to free the returned pointer.
173  * @param env The active Emacs environment.
174  * @param arg Emacs value representing a string.
175  * @param size Where the size will be stored.
176  * @return The string (owned pointer).
177  */
178 char *em_get_string_with_size(emacs_env *env, emacs_value arg, ptrdiff_t *size);
179 
180 /**
181  * Return a string from an emacs_value.
182  * Caller is responsible for ensuring that the value is a string, and to free the returned pointer.
183  * @param env The active Emacs environment.
184  * @param arg Emacs value representing a string.
185  * @return The string (owned pointer).
186  */
187 char *em_get_string(emacs_env *env, emacs_value arg);
188 
189 /**
190  * Call (cons car cdr) in Emacs.
191  * @param env The active Emacs environment.
192  * @param car The car.
193  * @param cdr The cdr.
194  * @return The cons cell.
195  */
196 emacs_value em_cons(emacs_env *env, emacs_value car, emacs_value cdr);
197 
198 /**
199  * Call (consp cell) in Emacs.
200  * @param env The active Emacs environment.
201  * @param cell The cell you're testing.
202  * @return True if cell is a cons cell, false otherwise.
203  */
204 bool em_consp(emacs_env *env, emacs_value cell);
205 
206 /**
207  * Call (car cell) in Emacs.
208  * @param env The active Emacs environment.
209  * @param cell the cell to get the car of.
210  * @return the car of the cell or nil.
211  */
212 emacs_value em_car(emacs_env *env, emacs_value cell);
213 
214 /**
215  * Call (cdr cell) in Emacs.
216  * @param env The active Emacs environment.
217  * @param cell the cell to get the cdr of.
218  * @return the cdr of the cell or nil.
219  */
220 emacs_value em_cdr(emacs_env *env, emacs_value cell);
221 
222 /**
223  * Call (list OBJECTS...) in Emacs.
224  * @param env The active Emacs environment.
225  * @param objects Array of objects.
226  * @param nobjects Number of \p objects.
227  */
228 emacs_value em_list(emacs_env *env, emacs_value *objects, ptrdiff_t nobjects);
229 
230 /**
231  * Call (listp OBJECT) in Emacs.
232  * @param env The active Emacs environment.
233  * @param object An emacs value.
234  */
235 bool em_listp(emacs_env *env, emacs_value object);
236 
237 /**
238  * Call (length SEQUENCE) in Emacs.
239  * @param env The active Emacs environment.
240  * @param object An emacs sequence.
241  * @return Length of the sequence, or -1 on error.
242  */
243 ptrdiff_t em_length(emacs_env *env, emacs_value sequence);
244 
245 /**
246  * Call (assq key list) in Emacs.
247  * @param env The active Emacs environment.
248  * @param key The key to lookup.
249  * @param list The associated list (alist).
250  * @return The first cons cell whose car is \p key.
251  */
252 emacs_value em_assq(emacs_env *env, emacs_value key, emacs_value list);
253 
254 /**
255  * Call (define-error SYMBOL MSG) in Emacs.
256  * @param env The active Emacs environment.
257  * @param symbol The error symbol.
258  * @param msg The error description.
259  * @param parent The parent error.
260  */
261 void em_define_error(emacs_env *env, emacs_value symbol, const char *msg, emacs_value parent);
262 
263 /**
264  * Define a function in Emacs, using defalias.
265  * @param env The active Emacs environment.
266  * @param name Symbol name of the desired function.
267  * @param func Function to bind.
268  */
269 void em_defun(emacs_env *env, const char *name, emacs_value func);
270 
271 /**
272  * Call (expand-file-name PATH) in Emacs.
273  * @param env The active Emacs environment.
274  * @param path The path to expand.
275  */
276 emacs_value em_expand_file_name(emacs_env *env, emacs_value path);
277 
278 /**
279  * Provide a feature to Emacs.
280  * @param env The active Emacs environment.
281  * @param name Symbol name of the feature to provide.
282  */
283 void em_provide(emacs_env *env, const char *feature);
284 
285 /**
286  * Check if a value is a user pointer.
287  * @param env The active Emacs environment.
288  * @param val Value to check.
289  * @return True iff val is a user pointer.
290  */
291 bool em_user_ptrp(emacs_env *env, emacs_value val);
292 
293 /**
294  * Return the value of default-directory in Emacs.
295  */
296 char *em_default_directory(emacs_env *env);
297 
298 /**
299  * Run (decode-time TIMESTAMP OFFSET) in Emacs.
300  */
301 emacs_value em_decode_time(emacs_env *env, intmax_t timestamp, intmax_t offset);
302 
303 /**
304  * Run (encode-time ...) in Emacs.
305  */
306 bool em_encode_time(emacs_env *env, emacs_value time, intmax_t *timestamp, intmax_t *offset);
307 
308 /**
309  * Run (insert ...) in Emacs.
310  */
311 void em_insert(emacs_env *env, const char *ptr, size_t length);
312 
313 /**
314  * Convert an emacs string to unibyte.
315  */
316 emacs_value em_string_as_unibyte(emacs_env *env, emacs_value str);
317 
318 
319 // =============================================================================
320 // Symbol <-> enum map functions
321 
322 bool em_findsym_branch(git_branch_t *out, emacs_env *env, emacs_value value, bool required);
323 bool em_findsym_checkout_strategy(git_checkout_strategy_t *out, emacs_env *env, emacs_value value, bool required);
324 bool em_findsym_config_level(git_config_level_t *out, emacs_env *env, emacs_value value, bool required);
325 bool em_findsym_delta(git_delta_t *out, emacs_env *env, emacs_value value, bool required);
326 bool em_findsym_diff_format(git_diff_format_t *out, emacs_env *env, emacs_value value, bool required);
327 bool em_findsym_diff_find(git_diff_find_t *out, emacs_env *env, emacs_value value, bool required);
328 bool em_findsym_describe_strategy(git_describe_strategy_t *out, emacs_env *env, emacs_value value, bool required);
329 bool em_findsym_fetch_prune(git_fetch_prune_t *out, emacs_env *env, emacs_value value, bool required);
330 bool em_findsym_filemode(git_filemode_t *out, emacs_env *env, emacs_value value, bool required);
331 bool em_findsym_merge_file_favor(git_merge_file_favor_t *out, emacs_env *env, emacs_value value, bool required);
332 bool em_findsym_otype(git_otype *out, emacs_env *env, emacs_value value, bool required);
333 bool em_findsym_pathspec_flag(git_pathspec_flag_t *out, emacs_env *env, emacs_value value, bool required);
334 bool em_findsym_proxy(git_proxy_t *out, emacs_env *env, emacs_value value, bool required);
335 bool em_findsym_remote_autotag_option(git_remote_autotag_option_t *out, emacs_env *env, emacs_value value, bool required);
336 bool em_findsym_reset(git_reset_t *out, emacs_env *env, emacs_value value, bool required);
337 bool em_findsym_submodule_ignore(git_submodule_ignore_t *out, emacs_env *env, emacs_value value, bool required);
338 bool em_findsym_submodule_recurse(git_submodule_recurse_t *out, emacs_env *env, emacs_value value, bool required);
339 bool em_findsym_submodule_update(git_submodule_update_t *out, emacs_env *env, emacs_value value, bool required);
340 bool em_findsym_stage(int *out, emacs_env *env, emacs_value value, bool required);
341 bool em_findsym_status_show(git_status_show_t *out, emacs_env *env, emacs_value value, bool required);
342 
343 emacs_value em_findenum_checkout_notify(git_checkout_notify_t value);
344 emacs_value em_findenum_delta(git_delta_t value);
345 emacs_value em_findenum_direction(git_direction value);
346 emacs_value em_findenum_error(git_error_t value);
347 emacs_value em_findenum_filemode(git_filemode_t value);
348 emacs_value em_findenum_merge_preference(git_merge_preference_t value);
349 emacs_value em_findenum_otype(git_otype value);
350 emacs_value em_findenum_submodule_ignore(git_submodule_ignore_t value);
351 emacs_value em_findenum_submodule_update(git_submodule_update_t value);
352 emacs_value em_findenum_submodule_recurse(git_submodule_recurse_t value);
353 emacs_value em_findenum_remote_autotag_option(git_remote_autotag_option_t value);
354 emacs_value em_findenum_repository_state(git_repository_state_t value);
355 emacs_value em_findenum_stage(int value);
356 
357 typedef bool setter(void *out, emacs_env *env, emacs_value value, bool on, bool required);
358 
359 setter em_setflag_checkout_notify;
360 setter em_setflag_diff_option;
361 setter em_setflag_index_add_option;
362 setter em_setflag_merge_file_flag;
363 setter em_setflag_merge_flag;
364 setter em_setflag_sort;
365 setter em_setflag_status_opt;
366 
367 bool em_setflags_list(void *out, emacs_env *env, emacs_value list, bool required, setter *setter);
368 bool em_setflags_alist(void *out, emacs_env *env, emacs_value alist, bool required, setter *setter);
369 
370 emacs_value em_getlist_credtype(emacs_env *env, git_credtype_t value);
371 emacs_value em_getlist_indexcap(emacs_env *env, int value);
372 emacs_value em_getlist_merge_analysis(emacs_env *env, git_merge_analysis_t value);
373 emacs_value em_getlist_status(emacs_env *env, git_status_t value);
374 emacs_value em_getlist_submodule_status(emacs_env *env, git_submodule_status_t value);
375 
376 bool em_checkflag_feature(emacs_value *out, emacs_env *env, emacs_value symbol, git_feature_t value, bool required);
377 bool em_checkflag_submodule_status(emacs_value *out, emacs_env *env, emacs_value symbol,
378                                    git_submodule_status_t value, bool required);
379 
380 #endif /* INTERFACE_H */
381