Fix typos
[TortoiseGit.git] / ext / gitdll / gitdll.c
blob7fa2950d88f0465d526e7fa547355681b7dc32b4
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2024 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // gitdll.cpp : Defines the exported functions for the DLL application.
22 #include "stdafx.h"
23 #include "../build/libgit-defines.h"
24 #pragma warning(push)
25 #pragma warning(disable: 4100 4267)
26 #include "git-compat-util.h"
27 #include "gitdll.h"
28 #include "read-cache.h"
29 #include "object-name.h"
30 #include "entry.h"
31 #include "commit.h"
32 #include "diff.h"
33 #include "packfile.h"
34 #include "revision.h"
35 #include "diffcore.h"
36 #include "dir.h"
37 #include "builtin.h"
38 #include "config.h"
39 #include "mailmap.h"
40 #include "tree.h"
41 #include "environment.h"
42 #include "setup.h"
43 #include "path.h"
44 #include "abspath.h"
45 #include "notes.h"
46 #pragma warning(pop)
48 extern char g_last_error[];
49 static const char* g_prefix;
51 /* also see GitHash.h */
52 static_assert(GIT_SHA1_RAWSZ <= LIBGIT_GIT_HASH_SIZE && GIT_SHA256_RAWSZ <= LIBGIT_GIT_HASH_SIZE && GIT_MAX_RAWSZ == LIBGIT_GIT_HASH_SIZE, "Required to be equal in gitdll.h");
53 static_assert(sizeof(struct object_id) == sizeof(struct GIT_OBJECT_OID), "Required to be equal in gitdll.h");
55 extern NORETURN void die_dll(const char* err, va_list params);
56 extern void handle_error(const char* err, va_list params);
57 extern void handle_warning(const char* warn, va_list params);
58 extern int die_is_recursing_dll(void);
60 extern void libgit_initialize(void);
61 extern void cleanup_chdir_notify(void);
62 extern void free_all_pack(void);
63 extern void reset_git_env(const LPWSTR*);
64 extern void drop_all_attr_stacks(void);
65 extern void git_atexit_dispatch(void);
66 extern void git_atexit_clear(void);
67 extern void invalidate_ref_cache(void);
68 extern void clear_ref_decorations(void);
69 extern void cmd_log_init(int argc, const char** argv, const char* prefix, struct rev_info* rev, struct setup_revision_opt* opt);
70 extern int estimate_commit_count(struct commit_list* list);
71 extern int log_tree_commit(struct rev_info*, struct commit*);
72 extern int write_entry(struct cache_entry* ce, char* path, struct conv_attrs* ca, const struct checkout* state, int to_tempfile, int* nr_checkouts);
73 extern void diff_flush_stat(struct diff_filepair* p, struct diff_options* o, struct diffstat_t* diffstat);
74 extern void free_diffstat_info(struct diffstat_t* diffstat);
75 static_assert(sizeof(unsigned long long) == sizeof(timestamp_t), "Required for each_reflog_ent_fn definition in gitdll.h");
76 extern int for_each_reflog_ent(const char* refname, each_reflog_ent_fn fn, void* cb_data);
78 void dll_entry(void)
80 set_die_routine(die_dll);
81 set_error_routine(handle_error);
82 set_warn_routine(handle_warning);
83 set_die_is_recursing_routine(die_is_recursing_dll);
84 libgit_initialize();
87 int git_get_sha1(const char *name, GIT_HASH sha1)
89 struct object_id oid = { 0 };
90 int ret = repo_get_oid(the_repository, name, &oid);
91 hashcpy(sha1, oid.hash);
92 return ret;
95 int git_init(const LPWSTR* env)
97 _fmode = _O_BINARY;
98 _setmode(_fileno(stdin), _O_BINARY);
99 _setmode(_fileno(stdout), _O_BINARY);
100 _setmode(_fileno(stderr), _O_BINARY);
102 cleanup_chdir_notify();
103 fscache_flush();
104 reset_git_env(env);
105 assert(getenv("HOME")); // make sure HOME is already set
106 drop_all_attr_stacks();
107 git_config_clear();
108 g_prefix = setup_git_directory();
109 git_config(git_default_config, NULL);
110 invalidate_ref_cache();
111 clear_ref_decorations();
113 /* add a safeguard until we have full support in TortoiseGit */
114 if (the_repository && the_repository->hash_algo && strcmp(the_repository->hash_algo->name, "sha1") != 0)
115 die("Only SHA1 is supported right now.");
117 return 0;
120 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR* author, const char* pbuff)
122 const char* end;
124 end=strchr(pbuff,'<');
125 if (!end || end - pbuff - 1 >= INT_MAX)
126 return -1;
127 author->Name = pbuff;
128 author->NameSize = (int)(end - pbuff - 1);
130 pbuff = end +1;
131 end = strchr(pbuff, '>');
132 if (!end || end[1] != ' ' || end - pbuff >= INT_MAX)
133 return -1;
134 author->Email = pbuff ;
135 author->EmailSize = (int)(end - pbuff);
137 pbuff = end + 2;
139 author->Date = parse_timestamp(pbuff, &end, 10);
140 if (end == pbuff || !end || *end != ' ' || end[1] != '+' && end[1] != '-' || !isdigit(end[2]) || !isdigit(end[3]) || !isdigit(end[4]) || !isdigit(end[5]))
141 return -1;
142 pbuff = end + 1;
143 author->TimeZone = strtol(pbuff, NULL, 10);
145 return 0;
148 int git_parse_commit(GIT_COMMIT *commit)
150 int ret = 0;
151 const char* pbuf;
152 const char* end;
153 struct commit *p;
155 p= (struct commit *)commit->m_pGitCommit;
157 memcpy(commit->m_hash, p->object.oid.hash, GIT_SHA1_RAWSZ);
159 commit->m_Encode = NULL;
160 commit->m_EncodeSize = 0;
162 commit->buffer = detach_commit_buffer(commit->m_pGitCommit, NULL);
164 pbuf = commit->buffer;
165 while(pbuf)
167 if (strncmp(pbuf, "author ", strlen("author ")) == 0)
169 ret = git_parse_commit_author(&commit->m_Author, pbuf + strlen("author "));
170 if(ret)
171 return -4;
173 else if (strncmp(pbuf, "committer ", strlen("committer ")) == 0)
175 ret = git_parse_commit_author(&commit->m_Committer, pbuf + strlen("committer "));
176 if(ret)
177 return -5;
179 pbuf = strchr(pbuf,'\n');
180 if(pbuf == NULL)
181 return -6;
183 else if (strncmp(pbuf, "encoding ", strlen("encoding ")) == 0)
185 pbuf += strlen("encoding ");
186 commit->m_Encode=pbuf;
187 end = strchr(pbuf,'\n');
188 if (!pbuf || end - pbuf >= INT_MAX)
189 return -7;
190 commit->m_EncodeSize= (int)(end -pbuf);
193 // the headers end after the first empty line
194 else if (*pbuf == '\n')
196 ++pbuf;
198 commit->m_Subject=pbuf;
199 end = strchr(pbuf,'\n');
200 if (!end)
202 size_t subjLen = strlen(pbuf);
203 if (subjLen >= INT_MAX)
204 return -8;
205 commit->m_SubjectSize = (int)subjLen;
207 else
209 size_t bodyLen;
210 if (end - pbuf >= INT_MAX)
211 return -9;
212 commit->m_SubjectSize = (int)(end - pbuf);
213 pbuf = end +1;
214 commit->m_Body = pbuf;
215 bodyLen = strlen(pbuf);
216 if (bodyLen >= INT_MAX)
217 return -10;
218 commit->m_BodySize = (int)bodyLen;
219 return 0;
223 pbuf = strchr(pbuf,'\n');
224 if(pbuf)
225 ++pbuf;
227 return 0;
230 int git_get_commit_from_hash(GIT_COMMIT* commit, const GIT_HASH hash)
232 int ret = 0;
234 struct commit *p;
235 struct object_id oid;
237 if (commit == NULL)
238 return -1;
240 memset(commit,0,sizeof(GIT_COMMIT));
242 hashcpy(oid.hash, hash);
243 oid.algo = 0;
245 commit->m_pGitCommit = p = lookup_commit(the_repository, &oid);
247 if(p == NULL)
248 return -1;
250 ret = repo_parse_commit(the_repository, p);
251 if( ret )
252 return ret;
254 return git_parse_commit(commit);
257 int git_get_commit_first_parent(const GIT_COMMIT* commit, GIT_COMMIT_LIST* list)
259 struct commit *p = commit->m_pGitCommit;
261 if(list == NULL)
262 return -1;
264 *list = (GIT_COMMIT_LIST*)p->parents;
265 return 0;
268 int git_commit_is_root(const GIT_COMMIT* commit)
270 struct commit* p = commit->m_pGitCommit;
271 return (struct commit_list**)p->parents ? 1 : 0;
274 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
276 struct commit_list *l;
277 if (list == NULL)
278 return -1;
280 l = *(struct commit_list **)list;
281 if (l == NULL)
282 return -1;
284 if(hash)
285 memcpy(hash, l->item->object.oid.hash, GIT_SHA1_RAWSZ);
287 *list = (GIT_COMMIT_LIST *)l->next;
288 return 0;
293 int git_free_commit(GIT_COMMIT *commit)
295 struct commit *p = commit->m_pGitCommit;
297 if( p->parents)
298 free_commit_list(p->parents);
300 if (p->maybe_tree)
301 free_tree_buffer(p->maybe_tree);
303 free_commit_buffer(the_repository->parsed_objects, p);
304 free((void*)commit->buffer);
306 p->object.parsed = 0;
307 p->parents = 0;
308 p->maybe_tree = NULL;
310 memset(commit,0,sizeof(GIT_COMMIT));
311 return 0;
314 static char** strtoargv(const char* arg, int* size)
316 int count=0;
317 const char* parg = arg;
318 char **argv;
319 char* p;
320 int i=0;
322 assert(arg && parg);
324 while (*parg)
326 if (*parg == ' ')
327 ++count;
328 assert(*parg != '\\' && "no backslashes allowed, use a Git path (with slashes) - no escaping of chars possible");
329 ++parg;
332 argv = malloc(strlen(arg) + 2 + (count + 3) * sizeof(char*)); // 1 char* for every parameter + 1 for argv[0] + 1 NULL as end end; and some space for the actual parameters: strlen() + 1 for \0, + 1 for \0 for argv[0]
333 if (!argv)
334 return NULL;
335 p = (char*)(argv + count + 3);
337 argv[i++] = p;
338 *p++ = '\0';
340 parg = arg;
341 while (*parg)
343 if (*parg != ' ')
345 char space=' ';
346 argv[i]=p;
348 while (*parg)
350 if (*parg == '"')
352 ++parg;
353 if(space == ' ')
354 space = '"';
355 else
356 space = ' ';
358 if (*parg == space || !*parg)
359 break;
361 *p++ = *parg++;
363 ++i;
364 *p++=0;
366 if (!*parg)
367 break;
368 ++parg;
370 argv[i]=NULL;
371 *size = i;
372 return argv;
374 int git_open_log(GIT_LOG* handle, const char* arg)
376 struct rev_info *p_Rev;
377 char ** argv=0;
378 int argc=0;
379 struct setup_revision_opt opt;
381 /* clear flags */
382 unsigned int obj_size = get_max_object_index();
383 for (unsigned int i = 0; i < obj_size; ++i)
385 struct object *ob= get_indexed_object(i);
386 if(ob)
388 ob->flags=0;
389 if (ob->parsed && ob->type == OBJ_COMMIT)
391 struct commit* commit = (struct commit*)ob;
392 free_commit_list(commit->parents);
393 commit->parents = NULL;
394 if (commit->maybe_tree)
395 free_tree_buffer(commit->maybe_tree);
396 commit->maybe_tree = NULL;
397 ob->parsed = 0;
402 argv = strtoargv(arg, &argc);
403 if (!argv)
404 return -1;
406 p_Rev = malloc(sizeof(struct rev_info));
407 if (p_Rev == NULL)
409 free(argv);
410 return -1;
413 memset(p_Rev,0,sizeof(struct rev_info));
415 invalidate_ref_cache();
416 clear_ref_decorations();
418 repo_init_revisions(the_repository, p_Rev, g_prefix);
419 p_Rev->diff = 1;
421 memset(&opt, 0, sizeof(opt));
422 opt.def = "HEAD";
424 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
426 p_Rev->pPrivate = argv;
427 *handle = p_Rev;
428 return 0;
431 int git_get_log_firstcommit(GIT_LOG handle)
433 return prepare_revision_walk(handle);
436 int git_get_log_estimate_commit_count(GIT_LOG handle)
438 struct rev_info *p_Rev;
439 p_Rev=(struct rev_info *)handle;
441 return estimate_commit_count(p_Rev->commits);
444 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
446 int ret =0;
448 if(commit == NULL)
449 return -1;
451 memset(commit, 0, sizeof(GIT_COMMIT));
453 commit->m_pGitCommit = get_revision(handle);
454 if( commit->m_pGitCommit == NULL)
455 return -2;
457 if (follow)
459 struct rev_info* p_Rev = (struct rev_info*)handle;
460 p_Rev->diffopt.no_free = 1;
461 if (!log_tree_commit(handle, commit->m_pGitCommit))
463 commit->m_ignore = 1;
464 return 0;
467 commit->m_ignore = 0;
469 ret=git_parse_commit(commit);
470 if(ret)
471 return ret;
473 return 0;
476 struct notes_tree **display_notes_trees;
477 int git_close_log(GIT_LOG handle, int releaseRevsisions)
479 if(handle)
481 struct rev_info *p_Rev;
482 p_Rev=(struct rev_info *)handle;
483 p_Rev->diffopt.no_free = 0;
484 if (releaseRevsisions)
485 release_revisions(p_Rev);
486 diff_free(&p_Rev->diffopt);
487 free(p_Rev->pPrivate);
488 free(handle);
490 free_all_pack();
492 if (display_notes_trees)
493 free_notes(*display_notes_trees);
494 display_notes_trees = 0;
495 return 0;
498 int git_open_diff(GIT_DIFF* diff, const char* arg)
500 struct rev_info *p_Rev;
501 char ** argv=0;
502 int argc=0;
504 argv = strtoargv(arg, &argc);
505 if (!argv)
506 return -1;
508 p_Rev = malloc(sizeof(struct rev_info));
509 if (!p_Rev)
510 return -1;
511 memset(p_Rev,0,sizeof(struct rev_info));
513 p_Rev->pPrivate = argv;
514 *diff = (GIT_DIFF)p_Rev;
516 repo_init_revisions(the_repository, p_Rev, g_prefix);
517 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
518 p_Rev->abbrev = 0;
519 p_Rev->diff = 1;
520 argc = setup_revisions(argc, argv, p_Rev, NULL);
522 return 0;
524 int git_close_diff(GIT_DIFF handle)
526 git_diff_flush(handle);
527 if(handle)
529 struct rev_info *p_Rev;
530 p_Rev=(struct rev_info *)handle;
531 free(p_Rev->pPrivate);
532 free(handle);
534 return 0;
536 int git_diff_flush(GIT_DIFF diff)
538 struct diff_queue_struct *q = &diff_queued_diff;
539 struct rev_info *p_Rev;
540 p_Rev = (struct rev_info *)diff;
542 if(q->nr == 0)
543 return 0;
545 for (int i = 0; i < q->nr; ++i)
546 diff_free_filepair(q->queue[i]);
548 if(q->queue)
550 free(q->queue);
551 q->queue = NULL;
552 q->nr = q->alloc = 0;
555 if (p_Rev->diffopt.close_file)
556 fclose(p_Rev->diffopt.file);
558 free_diffstat_info(&p_Rev->diffstat);
559 return 0;
562 int git_root_diff(GIT_DIFF diff, const GIT_HASH hash, GIT_FILE* file, int* count, int isstat)
564 struct object_id oid = { 0 };
565 struct rev_info *p_Rev;
566 struct diff_queue_struct *q = &diff_queued_diff;
568 p_Rev = (struct rev_info *)diff;
570 hashcpy(oid.hash, hash);
572 diff_root_tree_oid(&oid, "", &p_Rev->diffopt);
574 if(isstat)
576 diffcore_std(&p_Rev->diffopt);
578 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
579 for (int i = 0; i < q->nr; ++i) {
580 struct diff_filepair *p = q->queue[i];
581 //if (check_pair_status(p))
582 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
586 if (file)
587 *file = q;
588 if (count)
589 *count = q->nr;
591 return 0;
594 int git_do_diff(GIT_DIFF diff, const GIT_HASH hash1, const GIT_HASH hash2, GIT_FILE* file, int* count, int isstat)
596 struct rev_info *p_Rev;
597 struct object_id oid1, oid2;
598 struct diff_queue_struct *q = &diff_queued_diff;
600 p_Rev = (struct rev_info *)diff;
602 hashcpy(oid1.hash, hash1);
603 oid1.algo = 0;
604 hashcpy(oid2.hash, hash2);
605 oid2.algo = 0;
607 diff_tree_oid(&oid1, &oid2, "", &p_Rev->diffopt);
609 if(isstat)
611 diffcore_std(&p_Rev->diffopt);
612 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
613 for (int i = 0; i < q->nr; ++i) {
614 struct diff_filepair *p = q->queue[i];
615 //if (check_pair_status(p))
616 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
619 free_all_pack();
620 if(file)
621 *file = q;
622 if(count)
623 *count = q->nr;
624 return 0;
627 int git_get_diff_file(GIT_DIFF diff, GIT_FILE file, int i, char** newname, char** oldname, int* IsDir, char* status, int* IsBin, int* inc, int* dec)
629 struct diff_queue_struct *q = &diff_queued_diff;
630 struct rev_info *p_Rev;
631 p_Rev = (struct rev_info *)diff;
633 q = (struct diff_queue_struct *)file;
634 if(file == 0)
635 return -1;
636 if(i>=q->nr)
637 return -1;
639 assert(newname && oldname && status && IsDir);
641 *newname = q->queue[i]->two->path;
642 *oldname = q->queue[i]->one->path;
643 *status = q->queue[i]->status;
644 if (*status == 'D')
645 *IsDir = (q->queue[i]->one->mode & S_IFDIR) == S_IFDIR;
646 else
647 *IsDir = (q->queue[i]->two->mode & S_IFDIR) == S_IFDIR;
649 if (q->queue[i]->one->mode && q->queue[i]->two->mode && DIFF_PAIR_TYPE_CHANGED(q->queue[i]))
650 *IsDir = 0;
652 if(p_Rev->diffstat.files)
654 int j;
655 for (j = 0; j < p_Rev->diffstat.nr; ++j)
657 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
658 break;
660 if( j== p_Rev->diffstat.nr)
662 *IsBin=1;
663 *inc=0;
664 *dec=0;
665 return 0;
667 if(IsBin)
668 *IsBin = p_Rev->diffstat.files[j]->is_binary;
669 if(inc)
670 *inc = (int)p_Rev->diffstat.files[j]->added;
671 if(dec)
672 *dec = (int)p_Rev->diffstat.files[j]->deleted;
673 }else
675 *IsBin=1;
676 *inc=0;
677 *dec=0;
680 return 0;
683 int git_add_exclude(const char *string, const char *base,
684 int baselen, EXCLUDE_LIST which, int lineno)
686 add_pattern(string, base, baselen, which, lineno);
687 return 0;
690 int git_create_exclude_list(EXCLUDE_LIST *which)
692 *which = malloc(sizeof(struct pattern_list));
693 if (!*which)
694 return -1;
695 memset(*which, 0, sizeof(struct pattern_list));
696 return 0;
699 int git_free_exclude_list(EXCLUDE_LIST which)
701 struct pattern_list* p = (struct pattern_list*)which;
703 for (int i = 0; i < p->nr; ++i)
705 free(p->patterns[i]);
707 free(p->patterns);
708 free(p);
709 return 0;
712 int git_check_excluded_1(const char *pathname,
713 int pathlen, const char *basename, int *dtype,
714 EXCLUDE_LIST el, int ignorecase)
716 ignore_case = ignorecase;
717 return path_matches_pattern_list(pathname, pathlen, basename, dtype, el, NULL);
720 int git_get_notes(const GIT_HASH hash, char** p_note)
722 struct object_id oid;
723 struct strbuf sb;
724 size_t size;
725 strbuf_init(&sb,0);
726 hashcpy(oid.hash, hash);
727 oid.algo = 0;
728 format_display_notes(&oid, &sb, "utf-8", 1);
729 *p_note = strbuf_detach(&sb,&size);
731 return 0;
734 int git_update_index(void)
736 char** argv = NULL;
737 int argc = 0;
738 int ret;
740 argv = strtoargv("-q --refresh", &argc);
741 if (!argv)
742 return -1;
744 cleanup_chdir_notify();
745 drop_all_attr_stacks();
747 ret = cmd_update_index(argc, argv, NULL);
748 free(argv);
750 discard_index(the_repository->index);
751 free_all_pack();
753 return ret;
756 void git_exit_cleanup(void)
758 git_atexit_dispatch();
759 // do not clear the atexit list, as lots of methods register it just once (and have a local static int flag)
762 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
764 return for_each_reflog_ent(ref,fn,cb_data);
767 static int update_some(const struct object_id* sha1, struct strbuf* base, const char* pathname, unsigned mode, void* context)
769 struct cache_entry* ce = (struct cache_entry*)context;
771 if (S_ISDIR(mode))
772 return READ_TREE_RECURSIVE;
774 oidcpy(&ce->oid, sha1);
775 memcpy(ce->name, base->buf, base->len);
776 memcpy(ce->name + base->len, pathname, strlen(pathname));
777 ce->ce_flags = create_ce_flags((unsigned int)(strlen(pathname) + base->len));
778 ce->ce_mode = create_ce_mode(mode);
780 return 0;
783 int git_checkout_file(const char* ref, const char* path, char* outputpath)
785 struct cache_entry *ce;
786 int ret;
787 struct object_id oid;
788 struct tree * root;
789 struct checkout state = CHECKOUT_INIT;
790 struct pathspec pathspec;
791 struct conv_attrs ca;
792 const char *matchbuf[1];
793 ret = repo_get_oid(the_repository, ref, &oid);
794 if(ret)
795 return ret;
797 reprepare_packed_git(the_repository);
798 root = parse_tree_indirect(&oid);
800 if(!root)
802 free_all_pack();
803 return -1;
806 ce = xcalloc(1, cache_entry_size(strlen(path)));
808 matchbuf[0] = NULL;
809 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC, PATHSPEC_PREFER_CWD, path, matchbuf);
810 pathspec.items[0].nowildcard_len = pathspec.items[0].len;
811 ret = read_tree(the_repository, root, &pathspec, update_some, ce);
812 clear_pathspec(&pathspec);
814 if(ret)
816 free_all_pack();
817 free(ce);
818 return ret;
820 state.force = 1;
821 state.refresh_cache = 0;
822 state.istate = the_repository->index;
824 reset_parsed_attributes();
825 convert_attrs(state.istate, &ca, path);
827 ret = write_entry(ce, outputpath, &ca, &state, 0, NULL);
828 free_all_pack();
829 free(ce);
830 return ret;
832 struct config_buf
834 char *buf;
835 const char *key;
836 size_t size;
837 int seen;
840 static int get_config(const char* key_, const char* value_, const struct config_context* ctx, void* cb)
842 UNREFERENCED_PARAMETER(ctx);
843 struct config_buf *buf = (struct config_buf*)cb;
844 if(strcmp(key_, buf->key))
845 return 0;
847 if (value_)
848 strlcpy(buf->buf, value_, buf->size);
849 else
851 assert(buf->size >= 5);
852 buf->buf[0] = 't';
853 buf->buf[1] = 'r';
854 buf->buf[2] = 'u';
855 buf->buf[3] = 'e';
856 buf->buf[4] = 0;
858 buf->seen = 1;
859 return 0;
863 // wchar_t wrapper for git_etc_gitconfig()
864 const wchar_t *wget_msysgit_etc(const LPWSTR* env)
866 static const wchar_t *etc_gitconfig = NULL;
867 wchar_t wpointer[MAX_PATH];
869 if (etc_gitconfig)
870 return etc_gitconfig;
872 build_libgit_environment(env);
873 char* systemconfig = git_system_config();
874 if (xutftowcs_path(wpointer, systemconfig) < 0)
876 free(systemconfig);
877 return NULL;
879 free(systemconfig);
881 etc_gitconfig = _wcsdup(wpointer);
883 return etc_gitconfig;
886 int git_get_config(const char *key, char *buffer, int size)
888 char* system;
889 char* global = NULL;
890 char* globalxdg = NULL;
891 struct config_buf buf;
892 struct git_config_source config_source = { 0 };
894 struct config_options opts = { 0 };
895 opts.respect_includes = 1;
897 buf.buf=buffer;
898 buf.size=size;
899 buf.seen = 0;
900 buf.key = key;
902 if (have_git_dir())
904 opts.git_dir = get_git_dir();
905 char* local = git_pathdup("config");
906 config_source.file = local;
907 config_with_options(get_config, &buf, &config_source, the_repository, &opts);
908 free(local);
909 if (buf.seen)
910 return !buf.seen;
913 git_global_config(&global, &globalxdg);
914 if (globalxdg)
916 config_source.file = globalxdg;
917 config_with_options(get_config, &buf, &config_source, the_repository, &opts);
918 free(globalxdg);
919 globalxdg = NULL;
920 if (buf.seen)
922 free(global);
923 return !buf.seen;
926 if (global)
928 config_source.file = global;
929 config_with_options(get_config, &buf, &config_source, the_repository, &opts);
930 free(global);
931 global = NULL;
932 if (buf.seen)
933 return !buf.seen;
936 system = git_system_config();
937 if (system)
939 config_source.file = system;
940 config_with_options(get_config, &buf, &config_source, the_repository, &opts);
941 free(system);
942 system = NULL;
943 if (buf.seen)
944 return !buf.seen;
947 return !buf.seen;
950 const char* git_default_notes_ref(void)
952 return default_notes_ref();
955 int git_set_config(const char* key, const char* value, CONFIG_TYPE type)
957 char * config_exclusive_filename = NULL;
958 int ret;
960 switch(type)
962 case CONFIG_LOCAL:
963 if (!the_repository || !the_repository->gitdir)
964 die("repository not correctly initialized.");
965 config_exclusive_filename = git_pathdup("config");
966 break;
967 case CONFIG_GLOBAL:
968 case CONFIG_XDGGLOBAL:
970 char* global = NULL;
971 char* globalxdg = NULL;
972 git_global_config(&global, &globalxdg);
973 if (type == CONFIG_GLOBAL)
975 config_exclusive_filename = global;
976 global = NULL;
978 else
980 config_exclusive_filename = globalxdg;
981 globalxdg = NULL;
983 free(global);
984 free(globalxdg);
986 break;
989 if(!config_exclusive_filename)
990 return -1;
992 ret = git_config_set_multivar_in_file_gently(config_exclusive_filename, key, value, NULL, 0);
993 free(config_exclusive_filename);
994 return ret;
997 struct mailmap_info {
998 char *name;
999 char *email;
1002 struct mailmap_entry {
1003 /* name and email for the simple mail-only case */
1004 char *name;
1005 char *email;
1007 /* name and email for the complex mail and name matching case */
1008 struct string_list namemap;
1011 int git_read_mailmap(GIT_MAILMAP *mailmap)
1013 struct string_list *map;
1014 int result;
1016 if (!mailmap)
1017 return -1;
1019 *mailmap = NULL;
1020 if ((map = (struct string_list *)calloc(1, sizeof(struct string_list))) == NULL)
1021 return -1;
1023 if ((result = read_mailmap(map)) != 0)
1025 clear_mailmap(map);
1026 free(map);
1027 return result;
1030 if (!map->items)
1032 clear_mailmap(map);
1033 free(map);
1035 return -1;
1038 *mailmap = map;
1039 return 0;
1042 int git_lookup_mailmap(GIT_MAILMAP mailmap, const char** email1, const char** name1, const char* email2, void* payload, const char *(*author2_cb)(void*))
1044 struct string_list *map;
1045 struct string_list_item* si;
1046 struct mailmap_entry* me;
1048 if (!mailmap)
1049 return -1;
1051 map = (struct string_list *)mailmap;
1052 si = string_list_lookup(map, email2);
1053 if (!si)
1054 return -1;
1056 me = (struct mailmap_entry*)si->util;
1057 if (me->namemap.nr)
1059 /* The item has multiple items */
1060 const char* author2 = author2_cb(payload);
1061 struct string_list_item* subitem = string_list_lookup(&me->namemap, author2);
1062 if (subitem)
1063 me = (struct mailmap_entry*)subitem->util;
1066 if (email1)
1067 *email1 = me->email;
1068 if (name1)
1069 *name1 = me->name;
1070 return 0;
1073 void git_free_mailmap(GIT_MAILMAP mailmap)
1075 if (!mailmap)
1076 return;
1078 clear_mailmap((struct string_list *)mailmap);
1079 free(mailmap);
1082 // just for regression tests
1083 int git_mkdir(const char* path)
1085 return mkdir(path, 0);