Fix warnings
[TortoiseGit.git] / ext / gitdll / gitdll.c
blob8f8c437699349c7d0bd99b59ed8997a891fee9f6
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2022 - 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 "cache.h"
29 #include "entry.h"
30 #include "commit.h"
31 #include "diff.h"
32 #include "packfile.h"
33 #include "revision.h"
34 #include "diffcore.h"
35 #include "dir.h"
36 #include "builtin.h"
37 #include "config.h"
38 #include "mailmap.h"
39 #include "tree.h"
40 #pragma warning(pop)
42 extern char g_last_error[];
43 static const char* g_prefix;
45 /* also see GitHash.h */
46 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");
47 static_assert(sizeof(struct object_id) == sizeof(struct GIT_OBJECT_OID), "Required to be equal in gitdll.h");
49 extern NORETURN void die_dll(const char* err, va_list params);
50 extern void handle_error(const char* err, va_list params);
51 extern void handle_warning(const char* warn, va_list params);
52 extern int die_is_recursing_dll(void);
54 extern void libgit_initialize(void);
55 extern void cleanup_chdir_notify(void);
56 extern void free_all_pack(void);
57 extern void reset_git_env(void);
58 extern void drop_all_attr_stacks(void);
59 extern void git_atexit_dispatch(void);
60 extern void git_atexit_clear(void);
61 extern void invalidate_ref_cache(void);
62 extern void clear_ref_decorations(void);
63 extern void cmd_log_init(int argc, const char** argv, const char* prefix, struct rev_info* rev, struct setup_revision_opt* opt);
64 extern int estimate_commit_count(struct commit_list* list);
65 extern int log_tree_commit(struct rev_info*, struct commit*);
66 extern int write_entry(struct cache_entry* ce, char* path, struct conv_attrs* ca, const struct checkout* state, int to_tempfile);
67 extern void diff_flush_stat(struct diff_filepair* p, struct diff_options* o, struct diffstat_t* diffstat);
68 extern void free_diffstat_info(struct diffstat_t* diffstat);
69 static_assert(sizeof(unsigned long long) == sizeof(timestamp_t), "Required for each_reflog_ent_fn definition in gitdll.h");
70 extern int for_each_reflog_ent(const char* refname, each_reflog_ent_fn fn, void* cb_data);
72 void dll_entry(void)
74 set_die_routine(die_dll);
75 set_error_routine(handle_error);
76 set_warn_routine(handle_warning);
77 set_die_is_recursing_routine(die_is_recursing_dll);
78 libgit_initialize();
81 int git_get_sha1(const char *name, GIT_HASH sha1)
83 struct object_id oid = { 0 };
84 int ret = get_oid(name, &oid);
85 hashcpy(sha1, oid.hash);
86 return ret;
89 int git_init(void)
91 _fmode = _O_BINARY;
92 _setmode(_fileno(stdin), _O_BINARY);
93 _setmode(_fileno(stdout), _O_BINARY);
94 _setmode(_fileno(stderr), _O_BINARY);
96 cleanup_chdir_notify();
97 fscache_flush();
98 reset_git_env();
99 // set HOME if not set already
100 gitsetenv("HOME", get_windows_home_directory(), 0);
101 drop_all_attr_stacks();
102 git_config_clear();
103 g_prefix = setup_git_directory();
104 git_config(git_default_config, NULL);
105 invalidate_ref_cache();
106 clear_ref_decorations();
108 /* add a safeguard until we have full support in TortoiseGit */
109 if (the_repository && the_repository->hash_algo && strcmp(the_repository->hash_algo->name, "sha1") != 0)
110 die("Only SHA1 is supported right now.");
112 return 0;
115 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR* author, const char* pbuff)
117 const char* end;
119 author->Name=pbuff;
120 end=strchr(pbuff,'<');
121 if( end == 0)
123 return -1;
125 author->NameSize = (int)(end - pbuff - 1);
127 pbuff = end +1;
128 end = strchr(pbuff, '>');
129 if( end == 0)
130 return -1;
132 author->Email = pbuff ;
133 author->EmailSize = (int)(end - pbuff);
135 pbuff = end + 2;
137 author->Date = atoll(pbuff);
138 end = strchr(pbuff, ' ');
139 if( end == 0 )
140 return -1;
142 pbuff=end;
143 author->TimeZone = atol(pbuff);
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", 6) == 0)
169 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
170 if(ret)
171 return -4;
173 else if (strncmp(pbuf, "committer", 9) == 0)
175 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
176 if(ret)
177 return -5;
179 pbuf = strchr(pbuf,'\n');
180 if(pbuf == NULL)
181 return -6;
183 else if (strncmp(pbuf, "encoding", 8) == 0)
185 pbuf += 9;
186 commit->m_Encode=pbuf;
187 end = strchr(pbuf,'\n');
188 commit->m_EncodeSize= (int)(end -pbuf);
191 // the headers end after the first empty line
192 else if (*pbuf == '\n')
194 ++pbuf;
196 commit->m_Subject=pbuf;
197 end = strchr(pbuf,'\n');
198 if( end == 0)
199 commit->m_SubjectSize = (int)strlen(pbuf);
200 else
202 commit->m_SubjectSize = (int)(end - pbuf);
203 pbuf = end +1;
204 commit->m_Body = pbuf;
205 commit->m_BodySize = (int)strlen(pbuf);
206 return 0;
210 pbuf = strchr(pbuf,'\n');
211 if(pbuf)
212 ++pbuf;
214 return 0;
217 int git_get_commit_from_hash(GIT_COMMIT* commit, const GIT_HASH hash)
219 int ret = 0;
221 struct commit *p;
222 struct object_id oid;
224 if (commit == NULL)
225 return -1;
227 memset(commit,0,sizeof(GIT_COMMIT));
229 hashcpy(oid.hash, hash);
230 oid.algo = 0;
232 commit->m_pGitCommit = p = lookup_commit(the_repository, &oid);
234 if(p == NULL)
235 return -1;
237 ret = parse_commit(p);
238 if( ret )
239 return ret;
241 return git_parse_commit(commit);
244 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
246 struct commit *p = commit->m_pGitCommit;
248 if(list == NULL)
249 return -1;
251 *list = (GIT_COMMIT_LIST*)p->parents;
252 return 0;
255 int git_commit_is_root(const GIT_COMMIT* commit)
257 struct commit* p = commit->m_pGitCommit;
258 return (struct commit_list**)p->parents ? 1 : 0;
261 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
263 struct commit_list *l;
264 if (list == NULL)
265 return -1;
267 l = *(struct commit_list **)list;
268 if (l == NULL)
269 return -1;
271 if(hash)
272 memcpy(hash, l->item->object.oid.hash, GIT_SHA1_RAWSZ);
274 *list = (GIT_COMMIT_LIST *)l->next;
275 return 0;
280 int git_free_commit(GIT_COMMIT *commit)
282 struct commit *p = commit->m_pGitCommit;
284 if( p->parents)
285 free_commit_list(p->parents);
287 if (p->maybe_tree)
288 free_tree_buffer(p->maybe_tree);
290 free_commit_buffer(the_repository->parsed_objects, p);
291 free((void*)commit->buffer);
293 p->object.parsed = 0;
294 p->parents = 0;
295 p->maybe_tree = NULL;
297 memset(commit,0,sizeof(GIT_COMMIT));
298 return 0;
301 static char** strtoargv(const char* arg, int* size)
303 int count=0;
304 const char* parg = arg;
305 char **argv;
306 char* p;
307 int i=0;
309 assert(arg && parg);
311 while (*parg)
313 if (*parg == ' ')
314 ++count;
315 assert(*parg != '\\' && "no backslashes allowed, use a Git path (with slashes) - no escaping of chars possible");
316 ++parg;
319 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]
320 if (!argv)
321 return NULL;
322 p = (char*)(argv + count + 3);
324 argv[i++] = p;
325 *p++ = '\0';
327 parg = arg;
328 while (*parg)
330 if (*parg != ' ')
332 char space=' ';
333 argv[i]=p;
335 while (*parg)
337 if (*parg == '"')
339 ++parg;
340 if(space == ' ')
341 space = '"';
342 else
343 space = ' ';
345 if (*parg == space || !*parg)
346 break;
348 *p++ = *parg++;
350 ++i;
351 *p++=0;
353 if (!*parg)
354 break;
355 ++parg;
357 argv[i]=NULL;
358 *size = i;
359 return argv;
361 int git_open_log(GIT_LOG* handle, const char* arg)
363 struct rev_info *p_Rev;
364 char ** argv=0;
365 int argc=0;
366 struct setup_revision_opt opt;
368 /* clear flags */
369 unsigned int obj_size = get_max_object_index();
370 for (unsigned int i = 0; i < obj_size; ++i)
372 struct object *ob= get_indexed_object(i);
373 if(ob)
375 ob->flags=0;
376 if (ob->parsed && ob->type == OBJ_COMMIT)
378 struct commit* commit = (struct commit*)ob;
379 free_commit_list(commit->parents);
380 commit->parents = NULL;
381 if (commit->maybe_tree)
382 free_tree_buffer(commit->maybe_tree);
383 commit->maybe_tree = NULL;
384 ob->parsed = 0;
389 argv = strtoargv(arg, &argc);
390 if (!argv)
391 return -1;
393 p_Rev = malloc(sizeof(struct rev_info));
394 if (p_Rev == NULL)
396 free(argv);
397 return -1;
400 memset(p_Rev,0,sizeof(struct rev_info));
402 invalidate_ref_cache();
403 clear_ref_decorations();
405 init_revisions(p_Rev, g_prefix);
406 p_Rev->diff = 1;
408 memset(&opt, 0, sizeof(opt));
409 opt.def = "HEAD";
411 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
413 p_Rev->pPrivate = argv;
414 *handle = p_Rev;
415 return 0;
418 int git_get_log_firstcommit(GIT_LOG handle)
420 return prepare_revision_walk(handle);
423 int git_get_log_estimate_commit_count(GIT_LOG handle)
425 struct rev_info *p_Rev;
426 p_Rev=(struct rev_info *)handle;
428 return estimate_commit_count(p_Rev->commits);
431 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
433 int ret =0;
435 if(commit == NULL)
436 return -1;
438 memset(commit, 0, sizeof(GIT_COMMIT));
440 commit->m_pGitCommit = get_revision(handle);
441 if( commit->m_pGitCommit == NULL)
442 return -2;
444 if (follow && !log_tree_commit(handle, commit->m_pGitCommit))
446 commit->m_ignore = 1;
447 return 0;
449 commit->m_ignore = 0;
451 ret=git_parse_commit(commit);
452 if(ret)
453 return ret;
455 return 0;
458 struct notes_tree **display_notes_trees;
459 int git_close_log(GIT_LOG handle)
461 if(handle)
463 struct rev_info *p_Rev;
464 p_Rev=(struct rev_info *)handle;
465 clear_pathspec(&p_Rev->prune_data);
466 for (unsigned int i = 0; i < p_Rev->cmdline.nr; ++i)
467 free((void*)p_Rev->cmdline.rev[i].name);
468 free(p_Rev->cmdline.rev);
469 p_Rev->diffopt.no_free = 0;
470 diff_free(&p_Rev->diffopt);
471 free(p_Rev->pPrivate);
472 free(handle);
474 free_all_pack();
476 if (display_notes_trees)
477 free_notes(*display_notes_trees);
478 display_notes_trees = 0;
479 return 0;
482 int git_open_diff(GIT_DIFF* diff, const char* arg)
484 struct rev_info *p_Rev;
485 char ** argv=0;
486 int argc=0;
488 argv = strtoargv(arg, &argc);
489 if (!argv)
490 return -1;
492 p_Rev = malloc(sizeof(struct rev_info));
493 if (!p_Rev)
494 return -1;
495 memset(p_Rev,0,sizeof(struct rev_info));
497 p_Rev->pPrivate = argv;
498 *diff = (GIT_DIFF)p_Rev;
500 init_revisions(p_Rev, g_prefix);
501 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
502 p_Rev->abbrev = 0;
503 p_Rev->diff = 1;
504 argc = setup_revisions(argc, argv, p_Rev, NULL);
506 return 0;
508 int git_close_diff(GIT_DIFF handle)
510 git_diff_flush(handle);
511 if(handle)
513 struct rev_info *p_Rev;
514 p_Rev=(struct rev_info *)handle;
515 free(p_Rev->pPrivate);
516 free(handle);
518 return 0;
520 int git_diff_flush(GIT_DIFF diff)
522 struct diff_queue_struct *q = &diff_queued_diff;
523 struct rev_info *p_Rev;
524 p_Rev = (struct rev_info *)diff;
526 if(q->nr == 0)
527 return 0;
529 for (int i = 0; i < q->nr; ++i)
530 diff_free_filepair(q->queue[i]);
532 if(q->queue)
534 free(q->queue);
535 q->queue = NULL;
536 q->nr = q->alloc = 0;
539 if (p_Rev->diffopt.close_file)
540 fclose(p_Rev->diffopt.file);
542 free_diffstat_info(&p_Rev->diffstat);
543 return 0;
546 int git_root_diff(GIT_DIFF diff, const GIT_HASH hash, GIT_FILE* file, int* count, int isstat)
548 struct object_id oid = { 0 };
549 struct rev_info *p_Rev;
550 struct diff_queue_struct *q = &diff_queued_diff;
552 p_Rev = (struct rev_info *)diff;
554 hashcpy(oid.hash, hash);
556 diff_root_tree_oid(&oid, "", &p_Rev->diffopt);
558 if(isstat)
560 diffcore_std(&p_Rev->diffopt);
562 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
563 for (int i = 0; i < q->nr; ++i) {
564 struct diff_filepair *p = q->queue[i];
565 //if (check_pair_status(p))
566 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
570 if (file)
571 *file = q;
572 if (count)
573 *count = q->nr;
575 return 0;
578 int git_do_diff(GIT_DIFF diff, const GIT_HASH hash1, const GIT_HASH hash2, GIT_FILE* file, int* count, int isstat)
580 struct rev_info *p_Rev;
581 struct object_id oid1, oid2;
582 struct diff_queue_struct *q = &diff_queued_diff;
584 p_Rev = (struct rev_info *)diff;
586 hashcpy(oid1.hash, hash1);
587 oid1.algo = 0;
588 hashcpy(oid2.hash, hash2);
589 oid2.algo = 0;
591 diff_tree_oid(&oid1, &oid2, "", &p_Rev->diffopt);
593 if(isstat)
595 diffcore_std(&p_Rev->diffopt);
596 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
597 for (int i = 0; i < q->nr; ++i) {
598 struct diff_filepair *p = q->queue[i];
599 //if (check_pair_status(p))
600 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
603 free_all_pack();
604 if(file)
605 *file = q;
606 if(count)
607 *count = q->nr;
608 return 0;
611 int git_get_diff_file(GIT_DIFF diff, GIT_FILE file, int i, char** newname, char** oldname, int* IsDir, int* status, int* IsBin, int* inc, int* dec)
613 struct diff_queue_struct *q = &diff_queued_diff;
614 struct rev_info *p_Rev;
615 p_Rev = (struct rev_info *)diff;
617 q = (struct diff_queue_struct *)file;
618 if(file == 0)
619 return -1;
620 if(i>=q->nr)
621 return -1;
623 assert(newname && oldname && status && IsDir);
625 *newname = q->queue[i]->two->path;
626 *oldname = q->queue[i]->one->path;
627 *status = q->queue[i]->status;
628 if (*status == 'D')
629 *IsDir = (q->queue[i]->one->mode & S_IFDIR) == S_IFDIR;
630 else
631 *IsDir = (q->queue[i]->two->mode & S_IFDIR) == S_IFDIR;
633 if (q->queue[i]->one->mode && q->queue[i]->two->mode && DIFF_PAIR_TYPE_CHANGED(q->queue[i]))
634 *IsDir = 0;
636 if(p_Rev->diffstat.files)
638 int j;
639 for (j = 0; j < p_Rev->diffstat.nr; ++j)
641 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
642 break;
644 if( j== p_Rev->diffstat.nr)
646 *IsBin=1;
647 *inc=0;
648 *dec=0;
649 return 0;
651 if(IsBin)
652 *IsBin = p_Rev->diffstat.files[j]->is_binary;
653 if(inc)
654 *inc = (int)p_Rev->diffstat.files[j]->added;
655 if(dec)
656 *dec = (int)p_Rev->diffstat.files[j]->deleted;
657 }else
659 *IsBin=1;
660 *inc=0;
661 *dec=0;
664 return 0;
667 int git_add_exclude(const char *string, const char *base,
668 int baselen, EXCLUDE_LIST which, int lineno)
670 add_pattern(string, base, baselen, which, lineno);
671 return 0;
674 int git_create_exclude_list(EXCLUDE_LIST *which)
676 *which = malloc(sizeof(struct pattern_list));
677 if (!*which)
678 return -1;
679 memset(*which, 0, sizeof(struct pattern_list));
680 return 0;
683 int git_free_exclude_list(EXCLUDE_LIST which)
685 struct pattern_list* p = (struct pattern_list*)which;
687 for (int i = 0; i < p->nr; ++i)
689 free(p->patterns[i]);
691 free(p->patterns);
692 free(p);
693 return 0;
696 int git_check_excluded_1(const char *pathname,
697 int pathlen, const char *basename, int *dtype,
698 EXCLUDE_LIST el, int ignorecase)
700 ignore_case = ignorecase;
701 return path_matches_pattern_list(pathname, pathlen, basename, dtype, el, NULL);
704 int git_get_notes(const GIT_HASH hash, char** p_note)
706 struct object_id oid;
707 struct strbuf sb;
708 size_t size;
709 strbuf_init(&sb,0);
710 hashcpy(oid.hash, hash);
711 oid.algo = 0;
712 format_display_notes(&oid, &sb, "utf-8", 1);
713 *p_note = strbuf_detach(&sb,&size);
715 return 0;
718 int git_update_index(void)
720 char** argv = NULL;
721 int argc = 0;
722 int ret;
724 argv = strtoargv("-q --refresh", &argc);
725 if (!argv)
726 return -1;
728 cleanup_chdir_notify();
729 drop_all_attr_stacks();
731 ret = cmd_update_index(argc, argv, NULL);
732 free(argv);
734 discard_index(the_repository->index);
735 free_all_pack();
737 return ret;
740 void git_exit_cleanup(void)
742 git_atexit_dispatch();
743 // do not clear the atexit list, as lots of methods register it just once (and have a local static int flag)
746 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
748 return for_each_reflog_ent(ref,fn,cb_data);
751 static int update_some(const struct object_id* sha1, struct strbuf* base, const char* pathname, unsigned mode, void* context)
753 struct cache_entry* ce = (struct cache_entry*)context;
755 if (S_ISDIR(mode))
756 return READ_TREE_RECURSIVE;
758 oidcpy(&ce->oid, sha1);
759 memcpy(ce->name, base->buf, base->len);
760 memcpy(ce->name + base->len, pathname, strlen(pathname));
761 ce->ce_flags = create_ce_flags((unsigned int)(strlen(pathname) + base->len));
762 ce->ce_mode = create_ce_mode(mode);
764 return 0;
767 int git_checkout_file(const char* ref, const char* path, char* outputpath)
769 struct cache_entry *ce;
770 int ret;
771 struct object_id oid;
772 struct tree * root;
773 struct checkout state = CHECKOUT_INIT;
774 struct pathspec pathspec;
775 struct conv_attrs ca;
776 const char *matchbuf[1];
777 ret = get_oid(ref, &oid);
778 if(ret)
779 return ret;
781 reprepare_packed_git(the_repository);
782 root = parse_tree_indirect(&oid);
784 if(!root)
786 free_all_pack();
787 return -1;
790 ce = xcalloc(1, cache_entry_size(strlen(path)));
792 matchbuf[0] = NULL;
793 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC, PATHSPEC_PREFER_CWD, path, matchbuf);
794 pathspec.items[0].nowildcard_len = pathspec.items[0].len;
795 ret = read_tree(the_repository, root, &pathspec, update_some, ce);
796 clear_pathspec(&pathspec);
798 if(ret)
800 free_all_pack();
801 free(ce);
802 return ret;
804 state.force = 1;
805 state.refresh_cache = 0;
807 convert_attrs(state.istate, &ca, path);
809 ret = write_entry(ce, outputpath, &ca, &state, 0);
810 free_all_pack();
811 free(ce);
812 return ret;
814 struct config_buf
816 char *buf;
817 const char *key;
818 size_t size;
819 int seen;
822 static int get_config(const char *key_, const char *value_, void *cb)
824 struct config_buf *buf;
825 buf=(struct config_buf*)cb;
826 if(strcmp(key_, buf->key))
827 return 0;
829 if (value_)
830 strlcpy(buf->buf, value_, buf->size);
831 else
833 assert(buf->size >= 5);
834 buf->buf[0] = 't';
835 buf->buf[1] = 'r';
836 buf->buf[2] = 'u';
837 buf->buf[3] = 'e';
838 buf->buf[4] = 0;
840 buf->seen = 1;
841 return 0;
845 // wchar_t wrapper for git_etc_gitconfig()
846 const wchar_t *wget_msysgit_etc(void)
848 static const wchar_t *etc_gitconfig = NULL;
849 wchar_t wpointer[MAX_PATH];
851 if (etc_gitconfig)
852 return etc_gitconfig;
854 char* systemconfig = git_system_config();
855 if (xutftowcs_path(wpointer, systemconfig) < 0)
857 free(systemconfig);
858 return NULL;
860 free(systemconfig);
862 etc_gitconfig = _wcsdup(wpointer);
864 return etc_gitconfig;
867 int git_get_config(const char *key, char *buffer, int size)
869 const char *home;
870 char* system;
871 struct config_buf buf;
872 struct git_config_source config_source = { 0 };
874 struct config_options opts = { 0 };
875 opts.respect_includes = 1;
877 buf.buf=buffer;
878 buf.size=size;
879 buf.seen = 0;
880 buf.key = key;
882 if (have_git_dir())
884 opts.git_dir = get_git_dir();
885 char* local = git_pathdup("config");
886 config_source.file = local;
887 config_with_options(get_config, &buf, &config_source, &opts);
888 free(local);
889 if (buf.seen)
890 return !buf.seen;
893 home = get_windows_home_directory();
894 if (home)
896 char* global = mkpathdup("%s/.gitconfig", home);
897 if (global)
899 config_source.file = global;
900 config_with_options(get_config, &buf, &config_source, &opts);
901 free(global);
902 if (buf.seen)
903 return !buf.seen;
905 char* globalxdg = mkpathdup("%s/.config/git/config", home);
906 if (globalxdg)
908 config_source.file = globalxdg;
909 config_with_options(get_config, &buf, &config_source, &opts);
910 free(globalxdg);
911 if (buf.seen)
912 return !buf.seen;
916 system = git_system_config();
917 if (system)
919 config_source.file = system;
920 config_with_options(get_config, &buf, &config_source, &opts);
921 free(system);
922 if (buf.seen)
923 return !buf.seen;
926 return !buf.seen;
929 // taken from msysgit: compat/mingw.c
930 const char *get_windows_home_directory(void)
932 static const char *home_directory = NULL;
933 const char* tmp;
935 if (home_directory)
936 return home_directory;
938 if ((tmp = getenv("HOME")) != NULL && *tmp)
940 home_directory = _strdup(tmp);
941 return home_directory;
944 if ((tmp = getenv("HOMEDRIVE")) != NULL)
946 struct strbuf buf = STRBUF_INIT;
947 strbuf_addstr(&buf, tmp);
948 if ((tmp = getenv("HOMEPATH")) != NULL)
950 strbuf_addstr(&buf, tmp);
951 if (is_directory(buf.buf))
953 home_directory = strbuf_detach(&buf, NULL);
954 return home_directory;
957 strbuf_release(&buf);
960 if ((tmp = getenv("USERPROFILE")) != NULL && *tmp)
961 home_directory = _strdup(tmp);
963 return home_directory;
966 // wchar_t wrapper for get_windows_home_directory()
967 const wchar_t *wget_windows_home_directory(void)
969 static const wchar_t *home_directory = NULL;
970 wchar_t wpointer[MAX_PATH];
972 if (home_directory)
973 return home_directory;
975 if (xutftowcs_path(wpointer, get_windows_home_directory()) < 0)
976 return NULL;
978 home_directory = _wcsdup(wpointer);
980 return home_directory;
983 int get_set_config(const char *key, const char *value, CONFIG_TYPE type)
985 char * config_exclusive_filename = NULL;
986 int ret;
988 switch(type)
990 case CONFIG_LOCAL:
991 if (!the_repository || !the_repository->gitdir)
992 die("repository not correctly initialized.");
993 config_exclusive_filename = git_pathdup("config");
994 break;
995 case CONFIG_GLOBAL:
996 case CONFIG_XDGGLOBAL:
998 const char *home = get_windows_home_directory();
999 if (home)
1001 if (type == CONFIG_GLOBAL)
1002 config_exclusive_filename = mkpathdup("%s/.gitconfig", home);
1003 else
1004 config_exclusive_filename = mkpathdup("%s/.config/git/config", home);
1007 break;
1010 if(!config_exclusive_filename)
1011 return -1;
1013 ret = git_config_set_multivar_in_file_gently(config_exclusive_filename, key, value, NULL, 0);
1014 free(config_exclusive_filename);
1015 return ret;
1018 struct mailmap_info {
1019 char *name;
1020 char *email;
1023 struct mailmap_entry {
1024 /* name and email for the simple mail-only case */
1025 char *name;
1026 char *email;
1028 /* name and email for the complex mail and name matching case */
1029 struct string_list namemap;
1032 int git_read_mailmap(GIT_MAILMAP *mailmap)
1034 struct string_list *map;
1035 int result;
1037 if (!mailmap)
1038 return -1;
1040 *mailmap = NULL;
1041 if ((map = (struct string_list *)calloc(1, sizeof(struct string_list))) == NULL)
1042 return -1;
1044 if ((result = read_mailmap(map)) != 0)
1046 clear_mailmap(map);
1047 free(map);
1048 return result;
1051 if (!map->items)
1053 clear_mailmap(map);
1054 free(map);
1056 return -1;
1059 *mailmap = map;
1060 return 0;
1063 int git_lookup_mailmap(GIT_MAILMAP mailmap, const char** email1, const char** name1, const char* email2, void* payload, const char *(*author2_cb)(void*))
1065 struct string_list *map;
1066 struct string_list_item* si;
1067 struct mailmap_entry* me;
1069 if (!mailmap)
1070 return -1;
1072 map = (struct string_list *)mailmap;
1073 si = string_list_lookup(map, email2);
1074 if (!si)
1075 return -1;
1077 me = (struct mailmap_entry*)si->util;
1078 if (me->namemap.nr)
1080 /* The item has multiple items */
1081 const char* author2 = author2_cb(payload);
1082 struct string_list_item* subitem = string_list_lookup(&me->namemap, author2);
1083 if (subitem)
1084 me = (struct mailmap_entry*)subitem->util;
1087 if (email1)
1088 *email1 = me->email;
1089 if (name1)
1090 *name1 = me->name;
1091 return 0;
1094 void git_free_mailmap(GIT_MAILMAP mailmap)
1096 if (!mailmap)
1097 return;
1099 clear_mailmap((struct string_list *)mailmap);
1100 free(mailmap);
1103 // just for regression tests
1104 int git_mkdir(const char* path)
1106 return mkdir(path, 0);