Fixed issue #3033: Cannot view submodule log if repository sits under directory symlink
[TortoiseGit.git] / ext / gitdll / gitdll.c
bloba6a6b7338b177985e145e6f8232c3290bcad2924
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2017 - 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 4018 4127 4244 4267)
26 #include "git-compat-util.h"
27 #include "gitdll.h"
28 #include "cache.h"
29 #include "commit.h"
30 #include "diff.h"
31 #include "revision.h"
32 #include "diffcore.h"
33 #include "dir.h"
34 #include "builtin.h"
35 #include "exec_cmd.h"
36 #include "config.h"
37 #include "quote.h"
38 #include "run-command.h"
39 #include "mailmap.h"
40 #pragma warning(pop)
42 extern char g_last_error[];
43 const char * g_prefix;
45 extern NORETURN void die_dll(const char* err, va_list params);
46 extern void handle_error(const char* err, va_list params);
47 extern void handle_warning(const char* warn, va_list params);
48 extern int die_is_recursing_dll(void);
50 extern void free_all_pack(void);
51 extern void reset_git_env(void);
52 extern void drop_all_attr_stacks(void);
53 extern void git_atexit_dispatch(void);
54 extern void git_atexit_clear(void);
55 extern void invalidate_ref_cache(void);
56 extern void cmd_log_init(int argc, const char** argv, const char* prefix, struct rev_info* rev, struct setup_revision_opt* opt);
57 extern int estimate_commit_count(struct rev_info* rev, struct commit_list* list);
58 extern int log_tree_commit(struct rev_info*, struct commit*);
59 extern int write_entry(struct cache_entry* ce, char* path, const struct checkout* state, int to_tempfile);
60 extern struct object* deref_tag(struct object* o, const char* warn, int warnlen);
61 extern void diff_flush_stat(struct diff_filepair* p, struct diff_options* o, struct diffstat_t* diffstat);
62 extern void free_diffstat_info(struct diffstat_t* diffstat);
63 extern int for_each_reflog_ent(const char* refname, each_reflog_ent_fn fn, void* cb_data);
64 extern int for_each_ref_in(const char* prefix, each_ref_fn fn, void* cb_data);
66 void dll_entry(void)
68 set_die_routine(die_dll);
69 set_error_routine(handle_error);
70 set_warn_routine(handle_warning);
71 set_die_is_recursing_routine(die_is_recursing_dll);
74 int git_get_sha1(const char *name, GIT_HASH sha1)
76 return get_sha1(name,sha1);
79 static int convert_slash(char * path)
81 while(*path)
83 if(*path == '\\' )
84 *path = '/';
85 ++path;
87 return 0;
90 int git_init(void)
92 char path[MAX_PATH+1];
94 _fmode = _O_BINARY;
95 _setmode(_fileno(stdin), _O_BINARY);
96 _setmode(_fileno(stdout), _O_BINARY);
97 _setmode(_fileno(stderr), _O_BINARY);
99 GetModuleFileName(NULL, path, MAX_PATH);
100 convert_slash(path);
102 git_extract_argv0_path(path);
103 reset_git_env();
104 // set HOME if not set already
105 gitsetenv("HOME", get_windows_home_directory(), 0);
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();
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 = atol(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_HASH_SIZE);
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);
231 commit->m_pGitCommit = p = lookup_commit(&oid);
233 if(p == NULL)
234 return -1;
236 ret = parse_commit(p);
237 if( ret )
238 return ret;
240 return git_parse_commit(commit);
243 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
245 struct commit *p = commit->m_pGitCommit;
247 if(list == NULL)
248 return -1;
250 *list = (GIT_COMMIT_LIST*)p->parents;
251 return 0;
254 int git_commit_is_root(const GIT_COMMIT* commit)
256 struct commit* p = commit->m_pGitCommit;
257 return (struct commit_list**)p->parents ? 1 : 0;
260 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
262 struct commit_list *l;
263 if (list == NULL)
264 return -1;
266 l = *(struct commit_list **)list;
267 if (l == NULL)
268 return -1;
270 if(hash)
271 memcpy(hash, l->item->object.oid.hash, GIT_HASH_SIZE);
273 *list = (GIT_COMMIT_LIST *)l->next;
274 return 0;
279 int git_free_commit(GIT_COMMIT *commit)
281 struct commit *p = commit->m_pGitCommit;
283 if( p->parents)
284 free_commit_list(p->parents);
286 if (p->tree)
287 free_tree_buffer(p->tree);
289 #pragma warning(push)
290 #pragma warning(disable: 4090)
291 if (commit->buffer)
292 free(commit->buffer);
293 #pragma warning(pop)
295 p->object.parsed = 0;
296 p->parents = 0;
297 p->tree = 0;
299 memset(commit,0,sizeof(GIT_COMMIT));
300 return 0;
303 char **strtoargv(char *arg, int *size)
305 int count=0;
306 char *p=arg;
307 char **argv;
309 int i=0;
310 while(*p)
312 if(*p == '\\')
313 *p='/';
314 ++p;
316 p=arg;
318 while(*p)
320 if(*p == ' ')
321 ++count;
322 ++p;
325 argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));
326 p=(char*)(argv+count+2);
328 while(*arg)
330 if(*arg != ' ')
332 char space=' ';
333 argv[i]=p;
335 while(*arg)
337 if(*arg == '"')
339 ++arg;
340 if(space == ' ')
341 space = '"';
342 else
343 space = ' ';
345 if((*arg == space) || (*arg == 0))
346 break;
348 *p++ = *arg++;
350 ++i;
351 *p++=0;
353 if(*arg == 0)
354 break;
355 ++arg;
357 argv[i]=NULL;
358 *size = i;
359 return argv;
361 int git_open_log(GIT_LOG * handle, 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->tree)
382 free_tree_buffer(commit->tree);
383 commit->tree = NULL;
384 ob->parsed = 0;
389 if(arg != NULL)
390 argv = strtoargv(arg,&argc);
392 if (!argv)
393 return -1;
395 p_Rev = malloc(sizeof(struct rev_info));
396 if (p_Rev == NULL)
398 free(argv);
399 return -1;
402 memset(p_Rev,0,sizeof(struct rev_info));
404 invalidate_ref_cache();
406 init_revisions(p_Rev, g_prefix);
407 p_Rev->diff = 1;
409 memset(&opt, 0, sizeof(opt));
410 opt.def = "HEAD";
412 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
414 p_Rev->pPrivate = argv;
415 *handle = p_Rev;
416 return 0;
419 int git_get_log_firstcommit(GIT_LOG handle)
421 return prepare_revision_walk(handle);
424 int git_get_log_estimate_commit_count(GIT_LOG handle)
426 struct rev_info *p_Rev;
427 p_Rev=(struct rev_info *)handle;
429 return estimate_commit_count(p_Rev, p_Rev->commits);
432 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
434 int ret =0;
436 if(commit == NULL)
437 return -1;
439 memset(commit, 0, sizeof(GIT_COMMIT));
441 commit->m_pGitCommit = get_revision(handle);
442 if( commit->m_pGitCommit == NULL)
443 return -2;
445 if (follow && !log_tree_commit(handle, commit->m_pGitCommit))
447 commit->m_ignore = 1;
448 return 0;
450 commit->m_ignore = 0;
452 ret=git_parse_commit(commit);
453 if(ret)
454 return ret;
456 return 0;
459 struct notes_tree **display_notes_trees;
460 int git_close_log(GIT_LOG handle)
462 if(handle)
464 struct rev_info *p_Rev;
465 p_Rev=(struct rev_info *)handle;
466 if(p_Rev->pPrivate)
467 free(p_Rev->pPrivate);
468 free(handle);
470 free_all_pack();
472 if (display_notes_trees)
473 free_notes(*display_notes_trees);
474 display_notes_trees = 0;
475 return 0;
478 int git_open_diff(GIT_DIFF *diff, char * arg)
480 struct rev_info *p_Rev;
481 char ** argv=0;
482 int argc=0;
484 if(arg != NULL)
485 argv = strtoargv(arg,&argc);
487 p_Rev = malloc(sizeof(struct rev_info));
488 memset(p_Rev,0,sizeof(struct rev_info));
490 p_Rev->pPrivate = argv;
491 *diff = (GIT_DIFF)p_Rev;
493 init_revisions(p_Rev, g_prefix);
494 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
495 p_Rev->abbrev = 0;
496 p_Rev->diff = 1;
497 argc = setup_revisions(argc, argv, p_Rev, NULL);
499 return 0;
501 int git_close_diff(GIT_DIFF handle)
503 git_diff_flush(handle);
504 if(handle)
506 struct rev_info *p_Rev;
507 p_Rev=(struct rev_info *)handle;
508 if(p_Rev->pPrivate)
509 free(p_Rev->pPrivate);
510 free(handle);
512 return 0;
514 int git_diff_flush(GIT_DIFF diff)
516 struct diff_queue_struct *q = &diff_queued_diff;
517 struct rev_info *p_Rev;
518 p_Rev = (struct rev_info *)diff;
520 if(q->nr == 0)
521 return 0;
523 for (int i = 0; i < q->nr; ++i)
524 diff_free_filepair(q->queue[i]);
526 if(q->queue)
528 free(q->queue);
529 q->queue = NULL;
530 q->nr = q->alloc = 0;
533 if (p_Rev->diffopt.close_file)
534 fclose(p_Rev->diffopt.file);
536 free_diffstat_info(&p_Rev->diffstat);
537 return 0;
540 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count, int isstat)
542 int ret;
543 struct object_id oid;
544 struct rev_info *p_Rev;
545 struct diff_queue_struct *q = &diff_queued_diff;
547 p_Rev = (struct rev_info *)diff;
549 hashcpy(oid.hash, hash);
551 ret = diff_root_tree_oid(&oid, "", &p_Rev->diffopt);
553 if(ret)
554 return ret;
556 if(isstat)
558 diffcore_std(&p_Rev->diffopt);
560 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
561 for (int i = 0; i < q->nr; ++i) {
562 struct diff_filepair *p = q->queue[i];
563 //if (check_pair_status(p))
564 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
568 if (file)
569 *file = q;
570 if (count)
571 *count = q->nr;
573 return 0;
576 int git_do_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count,int isstat)
578 struct rev_info *p_Rev;
579 int ret;
580 struct object_id oid1, oid2;
581 struct diff_queue_struct *q = &diff_queued_diff;
583 p_Rev = (struct rev_info *)diff;
585 hashcpy(oid1.hash, hash1);
586 hashcpy(oid2.hash, hash2);
588 ret = diff_tree_oid(&oid1, &oid2, "", &p_Rev->diffopt);
589 if( ret )
591 free_all_pack();
592 return ret;
595 if(isstat)
597 diffcore_std(&p_Rev->diffopt);
598 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
599 for (int i = 0; i < q->nr; ++i) {
600 struct diff_filepair *p = q->queue[i];
601 //if (check_pair_status(p))
602 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
605 free_all_pack();
606 if(file)
607 *file = q;
608 if(count)
609 *count = q->nr;
610 return 0;
613 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)
615 struct diff_queue_struct *q = &diff_queued_diff;
616 struct rev_info *p_Rev;
617 p_Rev = (struct rev_info *)diff;
619 q = (struct diff_queue_struct *)file;
620 if(file == 0)
621 return -1;
622 if(i>=q->nr)
623 return -1;
625 assert(newname && oldname && status && IsDir);
627 *newname = q->queue[i]->two->path;
628 *oldname = q->queue[i]->one->path;
629 *status = q->queue[i]->status;
630 if (*status == 'D')
631 *IsDir = (q->queue[i]->one->mode & S_IFDIR) == S_IFDIR;
632 else
633 *IsDir = (q->queue[i]->two->mode & S_IFDIR) == S_IFDIR;
635 if (q->queue[i]->one->mode && q->queue[i]->two->mode && DIFF_PAIR_TYPE_CHANGED(q->queue[i]))
636 *IsDir = 0;
638 if(p_Rev->diffstat.files)
640 int j;
641 for (j = 0; j < p_Rev->diffstat.nr; ++j)
643 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
644 break;
646 if( j== p_Rev->diffstat.nr)
648 *IsBin=1;
649 *inc=0;
650 *dec=0;
651 return 0;
653 if(IsBin)
654 *IsBin = p_Rev->diffstat.files[j]->is_binary;
655 if(inc)
656 *inc = (int)p_Rev->diffstat.files[j]->added;
657 if(dec)
658 *dec = (int)p_Rev->diffstat.files[j]->deleted;
659 }else
661 *IsBin=1;
662 *inc=0;
663 *dec=0;
666 return 0;
669 int git_add_exclude(const char *string, const char *base,
670 int baselen, EXCLUDE_LIST which, int lineno)
672 add_exclude(string, base, baselen, which, lineno);
673 return 0;
676 int git_create_exclude_list(EXCLUDE_LIST *which)
678 *which = malloc(sizeof(struct exclude_list));
679 memset(*which,0,sizeof(struct exclude_list));
680 return 0;
683 int git_free_exclude_list(EXCLUDE_LIST which)
685 struct exclude_list *p = (struct exclude_list *) which;
687 for (int i = 0; i < p->nr; ++i)
689 free(p->excludes[i]);
691 free(p->excludes);
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 is_excluded_from_list(pathname, pathlen, basename, dtype, el, &the_index);
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 format_display_notes(&oid, &sb, "utf-8", 1);
712 *p_note = strbuf_detach(&sb,&size);
714 return 0;
717 struct cmd_struct {
718 const char *cmd;
719 int (*fn)(int, const char **, const char *);
720 int option;
723 #define RUN_SETUP (1<<0)
725 static struct cmd_struct commands[] = {
726 { "notes", cmd_notes, RUN_SETUP },
727 { "update-index", cmd_update_index, RUN_SETUP },
730 int git_run_cmd(char *cmd, char *arg)
733 char ** argv=0;
734 int argc=0;
736 git_init();
738 for (int i = 0; i < sizeof(commands) / sizeof(struct cmd_struct); ++i)
740 if(strcmp(cmd,commands[i].cmd)==0)
742 int ret;
743 if(arg != NULL)
744 argv = strtoargv(arg,&argc);
746 ret = commands[i].fn(argc, argv, NULL);
748 if(argv)
749 free(argv);
751 discard_cache();
752 free_all_pack();
754 return ret;
759 return -1;
762 void git_exit_cleanup(void)
764 git_atexit_dispatch();
765 git_atexit_clear();
768 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
770 return for_each_reflog_ent(ref,fn,cb_data);
773 static int update_some(const unsigned char* sha1, struct strbuf* base,
774 const char *pathname, unsigned mode, int stage, void *context)
776 struct cache_entry *ce;
777 UNREFERENCED_PARAMETER(stage);
779 ce = (struct cache_entry *)context;
781 if (S_ISDIR(mode))
782 return READ_TREE_RECURSIVE;
784 hashcpy(ce->oid.hash, sha1);
785 memcpy(ce->name, base->buf, base->len);
786 memcpy(ce->name + base->len, pathname, strlen(pathname));
787 ce->ce_flags = create_ce_flags((unsigned int)(strlen(pathname) + base->len));
788 ce->ce_mode = create_ce_mode(mode);
790 return 0;
793 int git_checkout_file(const char* ref, const char* path, char* outputpath)
795 struct cache_entry *ce;
796 int ret;
797 struct object_id oid;
798 struct tree * root;
799 struct checkout state;
800 struct pathspec pathspec;
801 const char *matchbuf[1];
802 ret = get_oid(ref, &oid);
803 if(ret)
804 return ret;
806 reprepare_packed_git();
807 root = parse_tree_indirect(&oid);
809 if(!root)
811 free_all_pack();
812 return -1;
815 ce = xcalloc(1, cache_entry_size(strlen(path)));
817 matchbuf[0] = NULL;
818 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC, PATHSPEC_PREFER_CWD, path, matchbuf);
819 pathspec.items[0].nowildcard_len = pathspec.items[0].len;
820 ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce);
821 clear_pathspec(&pathspec);
823 if(ret)
825 free_all_pack();
826 free(ce);
827 return ret;
829 memset(&state, 0, sizeof(state));
830 state.force = 1;
831 state.refresh_cache = 0;
833 ret = write_entry(ce, outputpath, &state, 0);
834 free_all_pack();
835 free(ce);
836 return ret;
838 struct config_buf
840 char *buf;
841 const char *key;
842 size_t size;
843 int seen;
846 static int get_config(const char *key_, const char *value_, void *cb)
848 struct config_buf *buf;
849 buf=(struct config_buf*)cb;
850 if(strcmp(key_, buf->key))
851 return 0;
853 if (value_)
854 strncpy(buf->buf,value_,buf->size);
855 else
857 buf->buf[0] = 't';
858 buf->buf[1] = 'r';
859 buf->buf[2] = 'u';
860 buf->buf[3] = 'e';
861 buf->buf[4] = 0;
863 buf->seen = 1;
864 return 0;
868 // wchar_t wrapper for program_data_config()
869 const wchar_t* wget_program_data_config(void)
871 static const wchar_t *programdata_git_config = NULL;
872 wchar_t wpointer[MAX_PATH];
874 if (programdata_git_config)
875 return programdata_git_config;
877 if (xutftowcs_path(wpointer, program_data_config()) < 0)
878 return NULL;
880 programdata_git_config = _wcsdup(wpointer);
882 return programdata_git_config;
885 // wchar_t wrapper for git_etc_gitconfig()
886 const wchar_t *wget_msysgit_etc(void)
888 static const wchar_t *etc_gitconfig = NULL;
889 wchar_t wpointer[MAX_PATH];
891 if (etc_gitconfig)
892 return etc_gitconfig;
894 if (xutftowcs_path(wpointer, git_etc_gitconfig()) < 0)
895 return NULL;
897 etc_gitconfig = _wcsdup(wpointer);
899 return etc_gitconfig;
902 int git_get_config(const char *key, char *buffer, int size)
904 const char *home, *system, *programdata;
905 struct config_buf buf;
906 struct git_config_source config_source = { 0 };
908 struct config_options opts = { 0 };
909 opts.respect_includes = 1;
911 buf.buf=buffer;
912 buf.size=size;
913 buf.seen = 0;
914 buf.key = key;
916 if (have_git_dir())
918 char* local = git_pathdup("config");
919 config_source.file = local;
920 config_with_options(get_config, &buf, &config_source, &opts);
921 free(local);
922 if (buf.seen)
923 return !buf.seen;
926 home = get_windows_home_directory();
927 if (home)
929 char* global = xstrdup(mkpath("%s/.gitconfig", home));
930 if (global)
932 config_source.file = global;
933 config_with_options(get_config, &buf, &config_source, &opts);
934 free(global);
935 if (buf.seen)
936 return !buf.seen;
938 char* globalxdg = xstrdup(mkpath("%s/.config/git/config", home));
939 if (globalxdg)
941 config_source.file = globalxdg;
942 config_with_options(get_config, &buf, &config_source, &opts);
943 free(globalxdg);
944 if (buf.seen)
945 return !buf.seen;
949 system = git_etc_gitconfig();
950 if (system)
952 config_source.file = system;
953 config_with_options(get_config, &buf, &config_source, &opts);
954 if (buf.seen)
955 return !buf.seen;
958 programdata = git_program_data_config();
959 if (programdata)
961 config_source.file = programdata;
962 config_with_options(get_config, &buf, &config_source, &opts);
965 return !buf.seen;
968 // taken from msysgit: compat/mingw.c
969 const char *get_windows_home_directory(void)
971 static const char *home_directory = NULL;
972 const char* tmp;
974 if (home_directory)
975 return home_directory;
977 if ((tmp = getenv("HOME")) != NULL && *tmp)
979 home_directory = _strdup(tmp);
980 return home_directory;
983 if ((tmp = getenv("HOMEDRIVE")) != NULL)
985 struct strbuf buf = STRBUF_INIT;
986 strbuf_addstr(&buf, tmp);
987 if ((tmp = getenv("HOMEPATH")) != NULL)
989 strbuf_addstr(&buf, tmp);
990 if (is_directory(buf.buf))
992 home_directory = strbuf_detach(&buf, NULL);
993 return home_directory;
996 strbuf_release(&buf);
999 if ((tmp = getenv("USERPROFILE")) != NULL && *tmp)
1000 home_directory = _strdup(tmp);
1002 return home_directory;
1005 // wchar_t wrapper for get_windows_home_directory()
1006 const wchar_t *wget_windows_home_directory(void)
1008 static const wchar_t *home_directory = NULL;
1009 wchar_t wpointer[MAX_PATH];
1011 if (home_directory)
1012 return home_directory;
1014 if (xutftowcs_path(wpointer, get_windows_home_directory()) < 0)
1015 return NULL;
1017 home_directory = _wcsdup(wpointer);
1019 return home_directory;
1022 int get_set_config(const char *key, const char *value, CONFIG_TYPE type)
1024 char * config_exclusive_filename = NULL;
1025 int ret;
1027 switch(type)
1029 case CONFIG_LOCAL:
1030 config_exclusive_filename = git_pathdup("config");
1031 break;
1032 case CONFIG_GLOBAL:
1033 case CONFIG_XDGGLOBAL:
1035 const char *home = get_windows_home_directory();
1036 if (home)
1038 if (type == CONFIG_GLOBAL)
1039 config_exclusive_filename = xstrdup(mkpath("%s/.gitconfig", home));
1040 else
1041 config_exclusive_filename = xstrdup(mkpath("%s/.config/git/config", home));
1044 break;
1047 if(!config_exclusive_filename)
1048 return -1;
1050 ret = git_config_set_multivar_in_file_gently(config_exclusive_filename, key, value, NULL, 0);
1051 free(config_exclusive_filename);
1052 return ret;
1055 struct mailmap_info {
1056 char *name;
1057 char *email;
1060 struct mailmap_entry {
1061 /* name and email for the simple mail-only case */
1062 char *name;
1063 char *email;
1065 /* name and email for the complex mail and name matching case */
1066 struct string_list namemap;
1069 int git_read_mailmap(GIT_MAILMAP *mailmap)
1071 struct string_list *map;
1072 int result;
1074 if (!mailmap)
1075 return -1;
1077 *mailmap = NULL;
1078 if ((map = (struct string_list *)calloc(1, sizeof(struct string_list))) == NULL)
1079 return -1;
1081 if ((result = read_mailmap(map, NULL)) != 0)
1083 clear_mailmap(map);
1084 free(map);
1085 return result;
1088 if (!map->items)
1090 clear_mailmap(map);
1091 free(map);
1093 return -1;
1096 *mailmap = map;
1097 return 0;
1100 int git_lookup_mailmap(GIT_MAILMAP mailmap, const char** email1, const char** name1, const char* email2, void* payload, const char *(*author2_cb)(void*))
1102 struct string_list *map;
1103 int imax, imin = 0;
1105 if (!mailmap)
1106 return -1;
1108 map = (struct string_list *)mailmap;
1109 imax = map->nr - 1;
1110 while (imax >= imin)
1112 int i = imin + ((imax - imin) / 2);
1113 struct string_list_item *si = (struct string_list_item *)&map->items[i];
1114 struct mailmap_entry *me = (struct mailmap_entry *)si->util;
1115 int comp = map->cmp(si->string, email2);
1117 if (!comp)
1119 if (me->namemap.nr)
1121 const char *author2 = author2_cb(payload);
1122 for (unsigned int j = 0; j < me->namemap.nr; ++j)
1124 struct string_list_item *sj = (struct string_list_item *)&me->namemap.items[j];
1125 struct mailmap_info *mi = (struct mailmap_info *)sj->util;
1127 if (!map->cmp(sj->string, author2))
1129 if (email1)
1130 *email1 = mi->email;
1131 if (name1)
1132 *name1 = mi->name;
1133 return 0;
1138 if (email1)
1139 *email1 = me->email;
1140 if (name1)
1141 *name1 = me->name;
1142 return 0;
1144 else if (comp < 0)
1145 imin = i + 1;
1146 else
1147 imax = i - 1;
1150 return -1;
1153 void git_free_mailmap(GIT_MAILMAP mailmap)
1155 if (!mailmap)
1156 return;
1158 clear_mailmap((struct string_list *)mailmap);
1159 free(mailmap);