Reset config cache on git_init
[TortoiseGit.git] / ext / gitdll / gitdll.c
blobd3d50ac37fc9d8ccfee9e34e0ad16f6cd1b35588
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 "cache.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 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_attr_stack(void);
53 extern void git_atexit_dispatch(void);
54 extern void git_atexit_clear(void);
55 extern void invalidate_ref_cache(const char* submodule);
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_attr_stack();
107 git_config_clear();
108 g_prefix = setup_git_directory();
109 git_config(git_default_config, NULL);
111 return 0;
114 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR* author, const char* pbuff)
116 const char* end;
118 author->Name=pbuff;
119 end=strchr(pbuff,'<');
120 if( end == 0)
122 return -1;
124 author->NameSize = (int)(end - pbuff - 1);
126 pbuff = end +1;
127 end = strchr(pbuff, '>');
128 if( end == 0)
129 return -1;
131 author->Email = pbuff ;
132 author->EmailSize = (int)(end - pbuff);
134 pbuff = end + 2;
136 author->Date = atol(pbuff);
137 end = strchr(pbuff, ' ');
138 if( end == 0 )
139 return -1;
141 pbuff=end;
142 author->TimeZone = atol(pbuff);
144 return 0;
147 int git_parse_commit(GIT_COMMIT *commit)
149 int ret = 0;
150 const char* pbuf;
151 const char* end;
152 struct commit *p;
154 p= (struct commit *)commit->m_pGitCommit;
156 memcpy(commit->m_hash, p->object.oid.hash, GIT_HASH_SIZE);
158 commit->m_Encode = NULL;
159 commit->m_EncodeSize = 0;
161 commit->buffer = detach_commit_buffer(commit->m_pGitCommit, NULL);
163 pbuf = commit->buffer;
164 while(pbuf)
166 if (strncmp(pbuf, "author", 6) == 0)
168 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
169 if(ret)
170 return -4;
172 else if (strncmp(pbuf, "committer", 9) == 0)
174 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
175 if(ret)
176 return -5;
178 pbuf = strchr(pbuf,'\n');
179 if(pbuf == NULL)
180 return -6;
182 else if (strncmp(pbuf, "encoding", 8) == 0)
184 pbuf += 9;
185 commit->m_Encode=pbuf;
186 end = strchr(pbuf,'\n');
187 commit->m_EncodeSize= (int)(end -pbuf);
190 // the headers end after the first empty line
191 else if (*pbuf == '\n')
193 ++pbuf;
195 commit->m_Subject=pbuf;
196 end = strchr(pbuf,'\n');
197 if( end == 0)
198 commit->m_SubjectSize = (int)strlen(pbuf);
199 else
201 commit->m_SubjectSize = (int)(end - pbuf);
202 pbuf = end +1;
203 commit->m_Body = pbuf;
204 commit->m_BodySize = (int)strlen(pbuf);
205 return 0;
209 pbuf = strchr(pbuf,'\n');
210 if(pbuf)
211 ++pbuf;
213 return 0;
216 int git_get_commit_from_hash(GIT_COMMIT* commit, const GIT_HASH hash)
218 int ret = 0;
220 struct commit *p;
222 if (commit == NULL)
223 return -1;
225 memset(commit,0,sizeof(GIT_COMMIT));
227 commit->m_pGitCommit = p = lookup_commit(hash);
229 if(p == NULL)
230 return -1;
232 ret = parse_commit(p);
233 if( ret )
234 return ret;
236 return git_parse_commit(commit);
239 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
241 struct commit *p = commit->m_pGitCommit;
243 if(list == NULL)
244 return -1;
246 *list = (GIT_COMMIT_LIST*)p->parents;
247 return 0;
250 int git_commit_is_root(const GIT_COMMIT* commit)
252 struct commit* p = commit->m_pGitCommit;
253 return (struct commit_list**)p->parents ? 1 : 0;
256 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
258 struct commit_list *l;
259 if (list == NULL)
260 return -1;
262 l = *(struct commit_list **)list;
263 if (l == NULL)
264 return -1;
266 if(hash)
267 memcpy(hash, l->item->object.oid.hash, GIT_HASH_SIZE);
269 *list = (GIT_COMMIT_LIST *)l->next;
270 return 0;
275 int git_free_commit(GIT_COMMIT *commit)
277 struct commit *p = commit->m_pGitCommit;
279 if( p->parents)
280 free_commit_list(p->parents);
282 if (p->tree)
283 free_tree_buffer(p->tree);
285 #pragma warning(push)
286 #pragma warning(disable: 4090)
287 if (commit->buffer)
288 free(commit->buffer);
289 #pragma warning(pop)
291 p->object.parsed = 0;
292 p->parents = 0;
293 p->tree = 0;
295 memset(commit,0,sizeof(GIT_COMMIT));
296 return 0;
299 char **strtoargv(char *arg, int *size)
301 int count=0;
302 char *p=arg;
303 char **argv;
305 int i=0;
306 while(*p)
308 if(*p == '\\')
309 *p='/';
310 ++p;
312 p=arg;
314 while(*p)
316 if(*p == ' ')
317 ++count;
318 ++p;
321 argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));
322 p=(char*)(argv+count+2);
324 while(*arg)
326 if(*arg != ' ')
328 char space=' ';
329 argv[i]=p;
331 while(*arg)
333 if(*arg == '"')
335 ++arg;
336 if(space == ' ')
337 space = '"';
338 else
339 space = ' ';
341 if((*arg == space) || (*arg == 0))
342 break;
344 *p++ = *arg++;
346 ++i;
347 *p++=0;
349 if(*arg == 0)
350 break;
351 ++arg;
353 argv[i]=NULL;
354 *size = i;
355 return argv;
357 int git_open_log(GIT_LOG * handle, char * arg)
359 struct rev_info *p_Rev;
360 char ** argv=0;
361 int argc=0;
362 struct setup_revision_opt opt;
364 /* clear flags */
365 unsigned int obj_size = get_max_object_index();
366 for (unsigned int i = 0; i < obj_size; ++i)
368 struct object *ob= get_indexed_object(i);
369 if(ob)
371 ob->flags=0;
372 if (ob->parsed && ob->type == OBJ_COMMIT)
374 struct commit* commit = (struct commit*)ob;
375 free_commit_list(commit->parents);
376 commit->parents = NULL;
377 if (commit->tree)
378 free_tree_buffer(commit->tree);
379 commit->tree = NULL;
380 ob->parsed = 0;
385 if(arg != NULL)
386 argv = strtoargv(arg,&argc);
388 if (!argv)
389 return -1;
391 p_Rev = malloc(sizeof(struct rev_info));
392 if (p_Rev == NULL)
394 free(argv);
395 return -1;
398 memset(p_Rev,0,sizeof(struct rev_info));
400 invalidate_ref_cache(NULL);
402 init_revisions(p_Rev, g_prefix);
403 p_Rev->diff = 1;
405 memset(&opt, 0, sizeof(opt));
406 opt.def = "HEAD";
408 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
410 p_Rev->pPrivate = argv;
411 *handle = p_Rev;
412 return 0;
415 int git_get_log_firstcommit(GIT_LOG handle)
417 return prepare_revision_walk(handle);
420 int git_get_log_estimate_commit_count(GIT_LOG handle)
422 struct rev_info *p_Rev;
423 p_Rev=(struct rev_info *)handle;
425 return estimate_commit_count(p_Rev, p_Rev->commits);
428 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
430 int ret =0;
432 if(commit == NULL)
433 return -1;
435 memset(commit, 0, sizeof(GIT_COMMIT));
437 commit->m_pGitCommit = get_revision(handle);
438 if( commit->m_pGitCommit == NULL)
439 return -2;
441 if (follow && !log_tree_commit(handle, commit->m_pGitCommit))
443 commit->m_ignore = 1;
444 return 0;
446 commit->m_ignore = 0;
448 ret=git_parse_commit(commit);
449 if(ret)
450 return ret;
452 return 0;
455 struct notes_tree **display_notes_trees;
456 int git_close_log(GIT_LOG handle)
458 if(handle)
460 struct rev_info *p_Rev;
461 p_Rev=(struct rev_info *)handle;
462 if(p_Rev->pPrivate)
463 free(p_Rev->pPrivate);
464 free(handle);
466 free_all_pack();
468 if (display_notes_trees)
469 free_notes(*display_notes_trees);
470 display_notes_trees = 0;
471 return 0;
474 int git_open_diff(GIT_DIFF *diff, char * arg)
476 struct rev_info *p_Rev;
477 char ** argv=0;
478 int argc=0;
480 if(arg != NULL)
481 argv = strtoargv(arg,&argc);
483 p_Rev = malloc(sizeof(struct rev_info));
484 memset(p_Rev,0,sizeof(struct rev_info));
486 p_Rev->pPrivate = argv;
487 *diff = (GIT_DIFF)p_Rev;
489 init_revisions(p_Rev, g_prefix);
490 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
491 p_Rev->abbrev = 0;
492 p_Rev->diff = 1;
493 argc = setup_revisions(argc, argv, p_Rev, NULL);
495 return 0;
497 int git_close_diff(GIT_DIFF handle)
499 git_diff_flush(handle);
500 if(handle)
502 struct rev_info *p_Rev;
503 p_Rev=(struct rev_info *)handle;
504 if(p_Rev->pPrivate)
505 free(p_Rev->pPrivate);
506 free(handle);
508 return 0;
510 int git_diff_flush(GIT_DIFF diff)
512 struct diff_queue_struct *q = &diff_queued_diff;
513 struct rev_info *p_Rev;
514 p_Rev = (struct rev_info *)diff;
516 if(q->nr == 0)
517 return 0;
519 for (int i = 0; i < q->nr; ++i)
520 diff_free_filepair(q->queue[i]);
522 if(q->queue)
524 free(q->queue);
525 q->queue = NULL;
526 q->nr = q->alloc = 0;
529 if (p_Rev->diffopt.close_file)
530 fclose(p_Rev->diffopt.file);
532 free_diffstat_info(&p_Rev->diffstat);
533 return 0;
536 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count, int isstat)
538 int ret;
539 struct rev_info *p_Rev;
540 struct diff_queue_struct *q = &diff_queued_diff;
542 p_Rev = (struct rev_info *)diff;
544 ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);
546 if(ret)
547 return ret;
549 if(isstat)
551 diffcore_std(&p_Rev->diffopt);
553 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
554 for (int i = 0; i < q->nr; ++i) {
555 struct diff_filepair *p = q->queue[i];
556 //if (check_pair_status(p))
557 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
561 if (file)
562 *file = q;
563 if (count)
564 *count = q->nr;
566 return 0;
569 int git_do_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count,int isstat)
571 struct rev_info *p_Rev;
572 int ret;
573 struct diff_queue_struct *q = &diff_queued_diff;
575 p_Rev = (struct rev_info *)diff;
577 ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);
578 if( ret )
580 free_all_pack();
581 return ret;
584 if(isstat)
586 diffcore_std(&p_Rev->diffopt);
587 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
588 for (int i = 0; i < q->nr; ++i) {
589 struct diff_filepair *p = q->queue[i];
590 //if (check_pair_status(p))
591 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
594 free_all_pack();
595 if(file)
596 *file = q;
597 if(count)
598 *count = q->nr;
599 return 0;
602 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)
604 struct diff_queue_struct *q = &diff_queued_diff;
605 struct rev_info *p_Rev;
606 p_Rev = (struct rev_info *)diff;
608 q = (struct diff_queue_struct *)file;
609 if(file == 0)
610 return -1;
611 if(i>=q->nr)
612 return -1;
614 assert(newname && oldname && status && IsDir);
616 *newname = q->queue[i]->two->path;
617 *oldname = q->queue[i]->one->path;
618 *status = q->queue[i]->status;
619 if (*status == 'D')
620 *IsDir = (q->queue[i]->one->mode & S_IFDIR) == S_IFDIR;
621 else
622 *IsDir = (q->queue[i]->two->mode & S_IFDIR) == S_IFDIR;
624 if (q->queue[i]->one->mode && q->queue[i]->two->mode && DIFF_PAIR_TYPE_CHANGED(q->queue[i]))
625 *IsDir = 0;
627 if(p_Rev->diffstat.files)
629 int j;
630 for (j = 0; j < p_Rev->diffstat.nr; ++j)
632 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
633 break;
635 if( j== p_Rev->diffstat.nr)
637 *IsBin=1;
638 *inc=0;
639 *dec=0;
640 return 0;
642 if(IsBin)
643 *IsBin = p_Rev->diffstat.files[j]->is_binary;
644 if(inc)
645 *inc = (int)p_Rev->diffstat.files[j]->added;
646 if(dec)
647 *dec = (int)p_Rev->diffstat.files[j]->deleted;
648 }else
650 *IsBin=1;
651 *inc=0;
652 *dec=0;
655 return 0;
658 int git_add_exclude(const char *string, const char *base,
659 int baselen, struct exclude_list *which, int lineno)
661 add_exclude(string, base, baselen, which, lineno);
662 return 0;
665 int git_create_exclude_list(EXCLUDE_LIST *which)
667 *which = malloc(sizeof(struct exclude_list));
668 memset(*which,0,sizeof(struct exclude_list));
669 return 0;
672 int git_free_exclude_list(EXCLUDE_LIST which)
674 struct exclude_list *p = (struct exclude_list *) which;
676 for (int i = 0; i < p->nr; ++i)
678 free(p->excludes[i]);
680 free(p->excludes);
681 free(p);
682 return 0;
685 int git_check_excluded_1(const char *pathname,
686 int pathlen, const char *basename, int *dtype,
687 EXCLUDE_LIST el)
689 return is_excluded_from_list(pathname, pathlen, basename, dtype, el);
692 int git_get_notes(const GIT_HASH hash, char** p_note)
694 struct strbuf sb;
695 size_t size;
696 strbuf_init(&sb,0);
697 format_display_notes(hash, &sb, "utf-8", 1);
698 *p_note = strbuf_detach(&sb,&size);
700 return 0;
703 struct cmd_struct {
704 const char *cmd;
705 int (*fn)(int, const char **, const char *);
706 int option;
709 #define RUN_SETUP (1<<0)
711 static struct cmd_struct commands[] = {
712 { "notes", cmd_notes, RUN_SETUP },
713 { "update-index", cmd_update_index, RUN_SETUP },
716 int git_run_cmd(char *cmd, char *arg)
719 char ** argv=0;
720 int argc=0;
722 git_init();
724 for (int i = 0; i < sizeof(commands) / sizeof(struct cmd_struct); ++i)
726 if(strcmp(cmd,commands[i].cmd)==0)
728 int ret;
729 if(arg != NULL)
730 argv = strtoargv(arg,&argc);
732 ret = commands[i].fn(argc, argv, NULL);
734 if(argv)
735 free(argv);
737 discard_cache();
738 free_all_pack();
740 return ret;
745 return -1;
748 void git_exit_cleanup(void)
750 git_atexit_dispatch();
751 git_atexit_clear();
754 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
756 return for_each_reflog_ent(ref,fn,cb_data);
759 static int update_some(const unsigned char* sha1, struct strbuf* base,
760 const char *pathname, unsigned mode, int stage, void *context)
762 struct cache_entry *ce;
763 UNREFERENCED_PARAMETER(stage);
765 ce = (struct cache_entry *)context;
767 if (S_ISDIR(mode))
768 return READ_TREE_RECURSIVE;
770 hashcpy(ce->oid.hash, sha1);
771 memcpy(ce->name, base->buf, base->len);
772 memcpy(ce->name + base->len, pathname, strlen(pathname));
773 ce->ce_flags = create_ce_flags((unsigned int)(strlen(pathname) + base->len));
774 ce->ce_mode = create_ce_mode(mode);
776 return 0;
779 int git_checkout_file(const char* ref, const char* path, char* outputpath)
781 struct cache_entry *ce;
782 int ret;
783 GIT_HASH sha1;
784 struct tree * root;
785 struct checkout state;
786 struct pathspec pathspec;
787 const char *matchbuf[1];
788 ret = get_sha1(ref, sha1);
789 if(ret)
790 return ret;
792 reprepare_packed_git();
793 root = parse_tree_indirect(sha1);
795 if(!root)
797 free_all_pack();
798 return -1;
801 ce = xcalloc(1, cache_entry_size(strlen(path)));
803 matchbuf[0] = NULL;
804 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC, PATHSPEC_PREFER_CWD, path, matchbuf);
805 pathspec.items[0].nowildcard_len = pathspec.items[0].len;
806 ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce);
807 clear_pathspec(&pathspec);
809 if(ret)
811 free_all_pack();
812 free(ce);
813 return ret;
815 memset(&state, 0, sizeof(state));
816 state.force = 1;
817 state.refresh_cache = 0;
819 ret = write_entry(ce, outputpath, &state, 0);
820 free_all_pack();
821 free(ce);
822 return ret;
824 struct config_buf
826 char *buf;
827 const char *key;
828 size_t size;
829 int seen;
832 static int get_config(const char *key_, const char *value_, void *cb)
834 struct config_buf *buf;
835 buf=(struct config_buf*)cb;
836 if(strcmp(key_, buf->key))
837 return 0;
839 if (value_)
840 strncpy(buf->buf,value_,buf->size);
841 else
843 buf->buf[0] = 't';
844 buf->buf[1] = 'r';
845 buf->buf[2] = 'u';
846 buf->buf[3] = 'e';
847 buf->buf[4] = 0;
849 buf->seen = 1;
850 return 0;
854 // wchar_t wrapper for program_data_config()
855 const wchar_t* wget_program_data_config(void)
857 static const wchar_t *programdata_git_config = NULL;
858 wchar_t wpointer[MAX_PATH];
860 if (programdata_git_config)
861 return programdata_git_config;
863 if (xutftowcs_path(wpointer, program_data_config()) < 0)
864 return NULL;
866 programdata_git_config = _wcsdup(wpointer);
868 return programdata_git_config;
871 // wchar_t wrapper for git_etc_gitconfig()
872 const wchar_t *wget_msysgit_etc(void)
874 static const wchar_t *etc_gitconfig = NULL;
875 wchar_t wpointer[MAX_PATH];
877 if (etc_gitconfig)
878 return etc_gitconfig;
880 if (xutftowcs_path(wpointer, git_etc_gitconfig()) < 0)
881 return NULL;
883 etc_gitconfig = _wcsdup(wpointer);
885 return etc_gitconfig;
888 int git_get_config(const char *key, char *buffer, int size)
890 char *local, *global, *globalxdg;
891 const char *home, *system, *programdata;
892 struct config_buf buf;
893 struct git_config_source config_source = { 0 };
895 buf.buf=buffer;
896 buf.size=size;
897 buf.seen = 0;
898 buf.key = key;
900 home = get_windows_home_directory();
901 if (home)
903 global = xstrdup(mkpath("%s/.gitconfig", home));
904 globalxdg = xstrdup(mkpath("%s/.config/git/config", home));
906 else
908 global = NULL;
909 globalxdg = NULL;
912 system = git_etc_gitconfig();
913 programdata = git_program_data_config();
915 local = git_pathdup("config");
917 if (!buf.seen)
919 config_source.file = local;
920 git_config_with_options(get_config, &buf, &config_source, 1);
922 if (!buf.seen && global)
924 config_source.file = global;
925 git_config_with_options(get_config, &buf, &config_source, 1);
927 if (!buf.seen && globalxdg)
929 config_source.file = globalxdg;
930 git_config_with_options(get_config, &buf, &config_source, 1);
932 if (!buf.seen && system)
934 config_source.file = system;
935 git_config_with_options(get_config, &buf, &config_source, 1);
937 if (!buf.seen && programdata)
939 config_source.file = programdata;
940 git_config_with_options(get_config, &buf, &config_source, 1);
943 if(local)
944 free(local);
945 if(global)
946 free(global);
947 if (globalxdg)
948 free(globalxdg);
950 return !buf.seen;
953 // taken from msysgit: compat/mingw.c
954 const char *get_windows_home_directory(void)
956 static const char *home_directory = NULL;
957 const char* tmp;
959 if (home_directory)
960 return home_directory;
962 if ((tmp = getenv("HOME")) != NULL && *tmp)
964 home_directory = _strdup(tmp);
965 return home_directory;
968 if ((tmp = getenv("HOMEDRIVE")) != NULL)
970 struct strbuf buf = STRBUF_INIT;
971 strbuf_addstr(&buf, tmp);
972 if ((tmp = getenv("HOMEPATH")) != NULL)
974 strbuf_addstr(&buf, tmp);
975 if (is_directory(buf.buf))
977 home_directory = strbuf_detach(&buf, NULL);
978 return home_directory;
981 strbuf_release(&buf);
984 if ((tmp = getenv("USERPROFILE")) != NULL && *tmp)
985 home_directory = _strdup(tmp);
987 return home_directory;
990 // wchar_t wrapper for get_windows_home_directory()
991 const wchar_t *wget_windows_home_directory(void)
993 static const wchar_t *home_directory = NULL;
994 wchar_t wpointer[MAX_PATH];
996 if (home_directory)
997 return home_directory;
999 if (xutftowcs_path(wpointer, get_windows_home_directory()) < 0)
1000 return NULL;
1002 home_directory = _wcsdup(wpointer);
1004 return home_directory;
1007 int get_set_config(const char *key, const char *value, CONFIG_TYPE type)
1009 char * config_exclusive_filename = NULL;
1010 int ret;
1012 switch(type)
1014 case CONFIG_LOCAL:
1015 config_exclusive_filename = git_pathdup("config");
1016 break;
1017 case CONFIG_GLOBAL:
1018 case CONFIG_XDGGLOBAL:
1020 const char *home = get_windows_home_directory();
1021 if (home)
1023 if (type == CONFIG_GLOBAL)
1024 config_exclusive_filename = xstrdup(mkpath("%s/.gitconfig", home));
1025 else
1026 config_exclusive_filename = xstrdup(mkpath("%s/.config/git/config", home));
1029 break;
1032 if(!config_exclusive_filename)
1033 return -1;
1035 ret = git_config_set_multivar_in_file_gently(config_exclusive_filename, key, value, NULL, 0);
1036 free(config_exclusive_filename);
1037 return ret;
1040 struct mailmap_info {
1041 char *name;
1042 char *email;
1045 struct mailmap_entry {
1046 /* name and email for the simple mail-only case */
1047 char *name;
1048 char *email;
1050 /* name and email for the complex mail and name matching case */
1051 struct string_list namemap;
1054 int git_read_mailmap(GIT_MAILMAP *mailmap)
1056 struct string_list *map;
1057 int result;
1059 if (!mailmap)
1060 return -1;
1062 *mailmap = NULL;
1063 if ((map = (struct string_list *)calloc(1, sizeof(struct string_list))) == NULL)
1064 return -1;
1066 if ((result = read_mailmap(map, NULL)) != 0)
1068 clear_mailmap(map);
1069 free(map);
1070 return result;
1073 if (!map->items)
1075 clear_mailmap(map);
1076 free(map);
1078 return -1;
1081 *mailmap = map;
1082 return 0;
1085 int git_lookup_mailmap(GIT_MAILMAP mailmap, const char** email1, const char** name1, const char* email2, void* payload, const char *(*author2_cb)(void*))
1087 struct string_list *map;
1088 int imax, imin = 0;
1090 if (!mailmap)
1091 return -1;
1093 map = (struct string_list *)mailmap;
1094 imax = map->nr - 1;
1095 while (imax >= imin)
1097 int i = imin + ((imax - imin) / 2);
1098 struct string_list_item *si = (struct string_list_item *)&map->items[i];
1099 struct mailmap_entry *me = (struct mailmap_entry *)si->util;
1100 int comp = map->cmp(si->string, email2);
1102 if (!comp)
1104 if (me->namemap.nr)
1106 const char *author2 = author2_cb(payload);
1107 for (unsigned int j = 0; j < me->namemap.nr; ++j)
1109 struct string_list_item *sj = (struct string_list_item *)&me->namemap.items[j];
1110 struct mailmap_info *mi = (struct mailmap_info *)sj->util;
1112 if (!map->cmp(sj->string, author2))
1114 if (email1)
1115 *email1 = mi->email;
1116 if (name1)
1117 *name1 = mi->name;
1118 return 0;
1123 if (email1)
1124 *email1 = me->email;
1125 if (name1)
1126 *name1 = me->name;
1127 return 0;
1129 else if (comp < 0)
1130 imin = i + 1;
1131 else
1132 imax = i - 1;
1135 return -1;
1138 void git_free_mailmap(GIT_MAILMAP mailmap)
1140 if (!mailmap)
1141 return;
1143 clear_mailmap((struct string_list *)mailmap);
1144 free(mailmap);