Do not clear the atexit list
[TortoiseGit.git] / ext / gitdll / gitdll.c
blob792d706d82bd73da64196e4f2c04b0c7d902440e
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2018 - 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 "packfile.h"
32 #include "revision.h"
33 #include "diffcore.h"
34 #include "dir.h"
35 #include "builtin.h"
36 #include "exec_cmd.h"
37 #include "config.h"
38 #include "quote.h"
39 #include "run-command.h"
40 #include "mailmap.h"
41 #pragma warning(pop)
43 extern char g_last_error[];
44 const char * g_prefix;
46 static_assert(sizeof(struct object_id) == sizeof(struct GIT_OBJECT_OID), "Required to be equal in gitdll.h");
48 extern NORETURN void die_dll(const char* err, va_list params);
49 extern void handle_error(const char* err, va_list params);
50 extern void handle_warning(const char* warn, va_list params);
51 extern int die_is_recursing_dll(void);
53 extern void libgit_initialize(void);
54 extern void free_all_pack(void);
55 extern void reset_git_env(void);
56 extern void drop_all_attr_stacks(void);
57 extern void git_atexit_dispatch(void);
58 extern void git_atexit_clear(void);
59 extern void invalidate_ref_cache(void);
60 extern void cmd_log_init(int argc, const char** argv, const char* prefix, struct rev_info* rev, struct setup_revision_opt* opt);
61 extern int estimate_commit_count(struct rev_info* rev, struct commit_list* list);
62 extern int log_tree_commit(struct rev_info*, struct commit*);
63 extern int write_entry(struct cache_entry* ce, char* path, const struct checkout* state, int to_tempfile);
64 extern struct object* deref_tag(struct object* o, const char* warn, int warnlen);
65 extern void diff_flush_stat(struct diff_filepair* p, struct diff_options* o, struct diffstat_t* diffstat);
66 extern void free_diffstat_info(struct diffstat_t* diffstat);
67 static_assert(sizeof(unsigned long long) == sizeof(timestamp_t), "Required for each_reflog_ent_fn definition in gitdll.h");
68 extern int for_each_reflog_ent(const char* refname, each_reflog_ent_fn fn, void* cb_data);
69 extern int for_each_ref_in(const char* prefix, each_ref_fn fn, void* cb_data);
71 void dll_entry(void)
73 set_die_routine(die_dll);
74 set_error_routine(handle_error);
75 set_warn_routine(handle_warning);
76 set_die_is_recursing_routine(die_is_recursing_dll);
77 libgit_initialize();
80 int git_get_sha1(const char *name, GIT_HASH sha1)
82 struct object_id oid = { 0 };
83 int ret = get_oid(name, &oid);
84 hashcpy(sha1, oid.hash);
85 return ret;
88 static int convert_slash(char * path)
90 while(*path)
92 if(*path == '\\' )
93 *path = '/';
94 ++path;
96 return 0;
99 int git_init(void)
101 char path[MAX_PATH+1];
103 _fmode = _O_BINARY;
104 _setmode(_fileno(stdin), _O_BINARY);
105 _setmode(_fileno(stdout), _O_BINARY);
106 _setmode(_fileno(stderr), _O_BINARY);
108 GetModuleFileName(NULL, path, MAX_PATH);
109 convert_slash(path);
111 git_extract_argv0_path(path);
112 reset_git_env();
113 // set HOME if not set already
114 gitsetenv("HOME", get_windows_home_directory(), 0);
115 drop_all_attr_stacks();
116 git_config_clear();
117 g_prefix = setup_git_directory();
118 git_config(git_default_config, NULL);
119 invalidate_ref_cache();
121 return 0;
124 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR* author, const char* pbuff)
126 const char* end;
128 author->Name=pbuff;
129 end=strchr(pbuff,'<');
130 if( end == 0)
132 return -1;
134 author->NameSize = (int)(end - pbuff - 1);
136 pbuff = end +1;
137 end = strchr(pbuff, '>');
138 if( end == 0)
139 return -1;
141 author->Email = pbuff ;
142 author->EmailSize = (int)(end - pbuff);
144 pbuff = end + 2;
146 author->Date = atol(pbuff);
147 end = strchr(pbuff, ' ');
148 if( end == 0 )
149 return -1;
151 pbuff=end;
152 author->TimeZone = atol(pbuff);
154 return 0;
157 int git_parse_commit(GIT_COMMIT *commit)
159 int ret = 0;
160 const char* pbuf;
161 const char* end;
162 struct commit *p;
164 p= (struct commit *)commit->m_pGitCommit;
166 memcpy(commit->m_hash, p->object.oid.hash, GIT_HASH_SIZE);
168 commit->m_Encode = NULL;
169 commit->m_EncodeSize = 0;
171 commit->buffer = detach_commit_buffer(commit->m_pGitCommit, NULL);
173 pbuf = commit->buffer;
174 while(pbuf)
176 if (strncmp(pbuf, "author", 6) == 0)
178 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
179 if(ret)
180 return -4;
182 else if (strncmp(pbuf, "committer", 9) == 0)
184 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
185 if(ret)
186 return -5;
188 pbuf = strchr(pbuf,'\n');
189 if(pbuf == NULL)
190 return -6;
192 else if (strncmp(pbuf, "encoding", 8) == 0)
194 pbuf += 9;
195 commit->m_Encode=pbuf;
196 end = strchr(pbuf,'\n');
197 commit->m_EncodeSize= (int)(end -pbuf);
200 // the headers end after the first empty line
201 else if (*pbuf == '\n')
203 ++pbuf;
205 commit->m_Subject=pbuf;
206 end = strchr(pbuf,'\n');
207 if( end == 0)
208 commit->m_SubjectSize = (int)strlen(pbuf);
209 else
211 commit->m_SubjectSize = (int)(end - pbuf);
212 pbuf = end +1;
213 commit->m_Body = pbuf;
214 commit->m_BodySize = (int)strlen(pbuf);
215 return 0;
219 pbuf = strchr(pbuf,'\n');
220 if(pbuf)
221 ++pbuf;
223 return 0;
226 int git_get_commit_from_hash(GIT_COMMIT* commit, const GIT_HASH hash)
228 int ret = 0;
230 struct commit *p;
231 struct object_id oid;
233 if (commit == NULL)
234 return -1;
236 memset(commit,0,sizeof(GIT_COMMIT));
238 hashcpy(oid.hash, hash);
240 commit->m_pGitCommit = p = lookup_commit(&oid);
242 if(p == NULL)
243 return -1;
245 ret = parse_commit(p);
246 if( ret )
247 return ret;
249 return git_parse_commit(commit);
252 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
254 struct commit *p = commit->m_pGitCommit;
256 if(list == NULL)
257 return -1;
259 *list = (GIT_COMMIT_LIST*)p->parents;
260 return 0;
263 int git_commit_is_root(const GIT_COMMIT* commit)
265 struct commit* p = commit->m_pGitCommit;
266 return (struct commit_list**)p->parents ? 1 : 0;
269 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
271 struct commit_list *l;
272 if (list == NULL)
273 return -1;
275 l = *(struct commit_list **)list;
276 if (l == NULL)
277 return -1;
279 if(hash)
280 memcpy(hash, l->item->object.oid.hash, GIT_HASH_SIZE);
282 *list = (GIT_COMMIT_LIST *)l->next;
283 return 0;
288 int git_free_commit(GIT_COMMIT *commit)
290 struct commit *p = commit->m_pGitCommit;
292 if( p->parents)
293 free_commit_list(p->parents);
295 if (p->tree)
296 free_tree_buffer(p->tree);
298 #pragma warning(push)
299 #pragma warning(disable: 4090)
300 if (commit->buffer)
301 free(commit->buffer);
302 #pragma warning(pop)
304 p->object.parsed = 0;
305 p->parents = 0;
306 p->tree = 0;
308 memset(commit,0,sizeof(GIT_COMMIT));
309 return 0;
312 char **strtoargv(char *arg, int *size)
314 int count=0;
315 char *p=arg;
316 char **argv;
318 int i=0;
319 while(*p)
321 if(*p == '\\')
322 *p='/';
323 ++p;
325 p=arg;
327 while(*p)
329 if(*p == ' ')
330 ++count;
331 ++p;
334 argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));
335 p=(char*)(argv+count+2);
337 while(*arg)
339 if(*arg != ' ')
341 char space=' ';
342 argv[i]=p;
344 while(*arg)
346 if(*arg == '"')
348 ++arg;
349 if(space == ' ')
350 space = '"';
351 else
352 space = ' ';
354 if((*arg == space) || (*arg == 0))
355 break;
357 *p++ = *arg++;
359 ++i;
360 *p++=0;
362 if(*arg == 0)
363 break;
364 ++arg;
366 argv[i]=NULL;
367 *size = i;
368 return argv;
370 int git_open_log(GIT_LOG * handle, char * arg)
372 struct rev_info *p_Rev;
373 char ** argv=0;
374 int argc=0;
375 struct setup_revision_opt opt;
377 /* clear flags */
378 unsigned int obj_size = get_max_object_index();
379 for (unsigned int i = 0; i < obj_size; ++i)
381 struct object *ob= get_indexed_object(i);
382 if(ob)
384 ob->flags=0;
385 if (ob->parsed && ob->type == OBJ_COMMIT)
387 struct commit* commit = (struct commit*)ob;
388 free_commit_list(commit->parents);
389 commit->parents = NULL;
390 if (commit->tree)
391 free_tree_buffer(commit->tree);
392 commit->tree = NULL;
393 ob->parsed = 0;
398 if(arg != NULL)
399 argv = strtoargv(arg,&argc);
401 if (!argv)
402 return -1;
404 p_Rev = malloc(sizeof(struct rev_info));
405 if (p_Rev == NULL)
407 free(argv);
408 return -1;
411 memset(p_Rev,0,sizeof(struct rev_info));
413 invalidate_ref_cache();
415 init_revisions(p_Rev, g_prefix);
416 p_Rev->diff = 1;
418 memset(&opt, 0, sizeof(opt));
419 opt.def = "HEAD";
421 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
423 p_Rev->pPrivate = argv;
424 *handle = p_Rev;
425 return 0;
428 int git_get_log_firstcommit(GIT_LOG handle)
430 return prepare_revision_walk(handle);
433 int git_get_log_estimate_commit_count(GIT_LOG handle)
435 struct rev_info *p_Rev;
436 p_Rev=(struct rev_info *)handle;
438 return estimate_commit_count(p_Rev, p_Rev->commits);
441 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
443 int ret =0;
445 if(commit == NULL)
446 return -1;
448 memset(commit, 0, sizeof(GIT_COMMIT));
450 commit->m_pGitCommit = get_revision(handle);
451 if( commit->m_pGitCommit == NULL)
452 return -2;
454 if (follow && !log_tree_commit(handle, commit->m_pGitCommit))
456 commit->m_ignore = 1;
457 return 0;
459 commit->m_ignore = 0;
461 ret=git_parse_commit(commit);
462 if(ret)
463 return ret;
465 return 0;
468 struct notes_tree **display_notes_trees;
469 int git_close_log(GIT_LOG handle)
471 if(handle)
473 struct rev_info *p_Rev;
474 p_Rev=(struct rev_info *)handle;
475 if(p_Rev->pPrivate)
476 free(p_Rev->pPrivate);
477 free(handle);
479 free_all_pack();
481 if (display_notes_trees)
482 free_notes(*display_notes_trees);
483 display_notes_trees = 0;
484 return 0;
487 int git_open_diff(GIT_DIFF *diff, char * arg)
489 struct rev_info *p_Rev;
490 char ** argv=0;
491 int argc=0;
493 if(arg != NULL)
494 argv = strtoargv(arg,&argc);
496 p_Rev = malloc(sizeof(struct rev_info));
497 memset(p_Rev,0,sizeof(struct rev_info));
499 p_Rev->pPrivate = argv;
500 *diff = (GIT_DIFF)p_Rev;
502 init_revisions(p_Rev, g_prefix);
503 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
504 p_Rev->abbrev = 0;
505 p_Rev->diff = 1;
506 argc = setup_revisions(argc, argv, p_Rev, NULL);
508 return 0;
510 int git_close_diff(GIT_DIFF handle)
512 git_diff_flush(handle);
513 if(handle)
515 struct rev_info *p_Rev;
516 p_Rev=(struct rev_info *)handle;
517 if(p_Rev->pPrivate)
518 free(p_Rev->pPrivate);
519 free(handle);
521 return 0;
523 int git_diff_flush(GIT_DIFF diff)
525 struct diff_queue_struct *q = &diff_queued_diff;
526 struct rev_info *p_Rev;
527 p_Rev = (struct rev_info *)diff;
529 if(q->nr == 0)
530 return 0;
532 for (int i = 0; i < q->nr; ++i)
533 diff_free_filepair(q->queue[i]);
535 if(q->queue)
537 free(q->queue);
538 q->queue = NULL;
539 q->nr = q->alloc = 0;
542 if (p_Rev->diffopt.close_file)
543 fclose(p_Rev->diffopt.file);
545 free_diffstat_info(&p_Rev->diffstat);
546 return 0;
549 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count, int isstat)
551 int ret;
552 struct object_id oid;
553 struct rev_info *p_Rev;
554 struct diff_queue_struct *q = &diff_queued_diff;
556 p_Rev = (struct rev_info *)diff;
558 hashcpy(oid.hash, hash);
560 ret = diff_root_tree_oid(&oid, "", &p_Rev->diffopt);
562 if(ret)
563 return ret;
565 if(isstat)
567 diffcore_std(&p_Rev->diffopt);
569 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
570 for (int i = 0; i < q->nr; ++i) {
571 struct diff_filepair *p = q->queue[i];
572 //if (check_pair_status(p))
573 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
577 if (file)
578 *file = q;
579 if (count)
580 *count = q->nr;
582 return 0;
585 int git_do_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count,int isstat)
587 struct rev_info *p_Rev;
588 int ret;
589 struct object_id oid1, oid2;
590 struct diff_queue_struct *q = &diff_queued_diff;
592 p_Rev = (struct rev_info *)diff;
594 hashcpy(oid1.hash, hash1);
595 hashcpy(oid2.hash, hash2);
597 ret = diff_tree_oid(&oid1, &oid2, "", &p_Rev->diffopt);
598 if( ret )
600 free_all_pack();
601 return ret;
604 if(isstat)
606 diffcore_std(&p_Rev->diffopt);
607 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
608 for (int i = 0; i < q->nr; ++i) {
609 struct diff_filepair *p = q->queue[i];
610 //if (check_pair_status(p))
611 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
614 free_all_pack();
615 if(file)
616 *file = q;
617 if(count)
618 *count = q->nr;
619 return 0;
622 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)
624 struct diff_queue_struct *q = &diff_queued_diff;
625 struct rev_info *p_Rev;
626 p_Rev = (struct rev_info *)diff;
628 q = (struct diff_queue_struct *)file;
629 if(file == 0)
630 return -1;
631 if(i>=q->nr)
632 return -1;
634 assert(newname && oldname && status && IsDir);
636 *newname = q->queue[i]->two->path;
637 *oldname = q->queue[i]->one->path;
638 *status = q->queue[i]->status;
639 if (*status == 'D')
640 *IsDir = (q->queue[i]->one->mode & S_IFDIR) == S_IFDIR;
641 else
642 *IsDir = (q->queue[i]->two->mode & S_IFDIR) == S_IFDIR;
644 if (q->queue[i]->one->mode && q->queue[i]->two->mode && DIFF_PAIR_TYPE_CHANGED(q->queue[i]))
645 *IsDir = 0;
647 if(p_Rev->diffstat.files)
649 int j;
650 for (j = 0; j < p_Rev->diffstat.nr; ++j)
652 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
653 break;
655 if( j== p_Rev->diffstat.nr)
657 *IsBin=1;
658 *inc=0;
659 *dec=0;
660 return 0;
662 if(IsBin)
663 *IsBin = p_Rev->diffstat.files[j]->is_binary;
664 if(inc)
665 *inc = (int)p_Rev->diffstat.files[j]->added;
666 if(dec)
667 *dec = (int)p_Rev->diffstat.files[j]->deleted;
668 }else
670 *IsBin=1;
671 *inc=0;
672 *dec=0;
675 return 0;
678 int git_add_exclude(const char *string, const char *base,
679 int baselen, EXCLUDE_LIST which, int lineno)
681 add_exclude(string, base, baselen, which, lineno);
682 return 0;
685 int git_create_exclude_list(EXCLUDE_LIST *which)
687 *which = malloc(sizeof(struct exclude_list));
688 memset(*which,0,sizeof(struct exclude_list));
689 return 0;
692 int git_free_exclude_list(EXCLUDE_LIST which)
694 struct exclude_list *p = (struct exclude_list *) which;
696 for (int i = 0; i < p->nr; ++i)
698 free(p->excludes[i]);
700 free(p->excludes);
701 free(p);
702 return 0;
705 int git_check_excluded_1(const char *pathname,
706 int pathlen, const char *basename, int *dtype,
707 EXCLUDE_LIST el, int ignorecase)
709 ignore_case = ignorecase;
710 return is_excluded_from_list(pathname, pathlen, basename, dtype, el, &the_index);
713 int git_get_notes(const GIT_HASH hash, char** p_note)
715 struct object_id oid;
716 struct strbuf sb;
717 size_t size;
718 strbuf_init(&sb,0);
719 hashcpy(oid.hash, hash);
720 format_display_notes(&oid, &sb, "utf-8", 1);
721 *p_note = strbuf_detach(&sb,&size);
723 return 0;
726 struct cmd_struct {
727 const char *cmd;
728 int (*fn)(int, const char **, const char *);
729 int option;
732 #define RUN_SETUP (1<<0)
734 static struct cmd_struct commands[] = {
735 { "update-index", cmd_update_index, RUN_SETUP },
738 int git_run_cmd(char *cmd, char *arg)
741 char ** argv=0;
742 int argc=0;
744 git_init();
746 for (int i = 0; i < sizeof(commands) / sizeof(struct cmd_struct); ++i)
748 if(strcmp(cmd,commands[i].cmd)==0)
750 int ret;
751 if(arg != NULL)
752 argv = strtoargv(arg,&argc);
754 ret = commands[i].fn(argc, argv, NULL);
756 if(argv)
757 free(argv);
759 discard_cache();
760 free_all_pack();
762 return ret;
767 return -1;
770 void git_exit_cleanup(void)
772 git_atexit_dispatch();
773 // do not clear the atexit list, as lots of methods register it just once (and have a local static int flag)
776 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
778 return for_each_reflog_ent(ref,fn,cb_data);
781 static int update_some(const unsigned char* sha1, struct strbuf* base,
782 const char *pathname, unsigned mode, int stage, void *context)
784 struct cache_entry *ce;
785 UNREFERENCED_PARAMETER(stage);
787 ce = (struct cache_entry *)context;
789 if (S_ISDIR(mode))
790 return READ_TREE_RECURSIVE;
792 hashcpy(ce->oid.hash, sha1);
793 memcpy(ce->name, base->buf, base->len);
794 memcpy(ce->name + base->len, pathname, strlen(pathname));
795 ce->ce_flags = create_ce_flags((unsigned int)(strlen(pathname) + base->len));
796 ce->ce_mode = create_ce_mode(mode);
798 return 0;
801 int git_checkout_file(const char* ref, const char* path, char* outputpath)
803 struct cache_entry *ce;
804 int ret;
805 struct object_id oid;
806 struct tree * root;
807 struct checkout state;
808 struct pathspec pathspec;
809 const char *matchbuf[1];
810 ret = get_oid(ref, &oid);
811 if(ret)
812 return ret;
814 reprepare_packed_git();
815 root = parse_tree_indirect(&oid);
817 if(!root)
819 free_all_pack();
820 return -1;
823 ce = xcalloc(1, cache_entry_size(strlen(path)));
825 matchbuf[0] = NULL;
826 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC, PATHSPEC_PREFER_CWD, path, matchbuf);
827 pathspec.items[0].nowildcard_len = pathspec.items[0].len;
828 ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce);
829 clear_pathspec(&pathspec);
831 if(ret)
833 free_all_pack();
834 free(ce);
835 return ret;
837 memset(&state, 0, sizeof(state));
838 state.force = 1;
839 state.refresh_cache = 0;
841 ret = write_entry(ce, outputpath, &state, 0);
842 free_all_pack();
843 free(ce);
844 return ret;
846 struct config_buf
848 char *buf;
849 const char *key;
850 size_t size;
851 int seen;
854 static int get_config(const char *key_, const char *value_, void *cb)
856 struct config_buf *buf;
857 buf=(struct config_buf*)cb;
858 if(strcmp(key_, buf->key))
859 return 0;
861 if (value_)
862 strncpy(buf->buf,value_,buf->size);
863 else
865 buf->buf[0] = 't';
866 buf->buf[1] = 'r';
867 buf->buf[2] = 'u';
868 buf->buf[3] = 'e';
869 buf->buf[4] = 0;
871 buf->seen = 1;
872 return 0;
876 // wchar_t wrapper for program_data_config()
877 const wchar_t* wget_program_data_config(void)
879 static const wchar_t *programdata_git_config = NULL;
880 wchar_t wpointer[MAX_PATH];
882 if (programdata_git_config)
883 return programdata_git_config;
885 if (xutftowcs_path(wpointer, program_data_config()) < 0)
886 return NULL;
888 programdata_git_config = _wcsdup(wpointer);
890 return programdata_git_config;
893 // wchar_t wrapper for git_etc_gitconfig()
894 const wchar_t *wget_msysgit_etc(void)
896 static const wchar_t *etc_gitconfig = NULL;
897 wchar_t wpointer[MAX_PATH];
899 if (etc_gitconfig)
900 return etc_gitconfig;
902 if (xutftowcs_path(wpointer, git_etc_gitconfig()) < 0)
903 return NULL;
905 etc_gitconfig = _wcsdup(wpointer);
907 return etc_gitconfig;
910 int git_get_config(const char *key, char *buffer, int size)
912 const char *home, *system, *programdata;
913 struct config_buf buf;
914 struct git_config_source config_source = { 0 };
916 struct config_options opts = { 0 };
917 opts.respect_includes = 1;
919 buf.buf=buffer;
920 buf.size=size;
921 buf.seen = 0;
922 buf.key = key;
924 if (have_git_dir())
926 opts.git_dir = get_git_dir();
927 char* local = git_pathdup("config");
928 config_source.file = local;
929 config_with_options(get_config, &buf, &config_source, &opts);
930 free(local);
931 if (buf.seen)
932 return !buf.seen;
935 home = get_windows_home_directory();
936 if (home)
938 char* global = xstrdup(mkpath("%s/.gitconfig", home));
939 if (global)
941 config_source.file = global;
942 config_with_options(get_config, &buf, &config_source, &opts);
943 free(global);
944 if (buf.seen)
945 return !buf.seen;
947 char* globalxdg = xstrdup(mkpath("%s/.config/git/config", home));
948 if (globalxdg)
950 config_source.file = globalxdg;
951 config_with_options(get_config, &buf, &config_source, &opts);
952 free(globalxdg);
953 if (buf.seen)
954 return !buf.seen;
958 system = git_etc_gitconfig();
959 if (system)
961 config_source.file = system;
962 config_with_options(get_config, &buf, &config_source, &opts);
963 if (buf.seen)
964 return !buf.seen;
967 programdata = git_program_data_config();
968 if (programdata)
970 config_source.file = programdata;
971 config_with_options(get_config, &buf, &config_source, &opts);
974 return !buf.seen;
977 // taken from msysgit: compat/mingw.c
978 const char *get_windows_home_directory(void)
980 static const char *home_directory = NULL;
981 const char* tmp;
983 if (home_directory)
984 return home_directory;
986 if ((tmp = getenv("HOME")) != NULL && *tmp)
988 home_directory = _strdup(tmp);
989 return home_directory;
992 if ((tmp = getenv("HOMEDRIVE")) != NULL)
994 struct strbuf buf = STRBUF_INIT;
995 strbuf_addstr(&buf, tmp);
996 if ((tmp = getenv("HOMEPATH")) != NULL)
998 strbuf_addstr(&buf, tmp);
999 if (is_directory(buf.buf))
1001 home_directory = strbuf_detach(&buf, NULL);
1002 return home_directory;
1005 strbuf_release(&buf);
1008 if ((tmp = getenv("USERPROFILE")) != NULL && *tmp)
1009 home_directory = _strdup(tmp);
1011 return home_directory;
1014 // wchar_t wrapper for get_windows_home_directory()
1015 const wchar_t *wget_windows_home_directory(void)
1017 static const wchar_t *home_directory = NULL;
1018 wchar_t wpointer[MAX_PATH];
1020 if (home_directory)
1021 return home_directory;
1023 if (xutftowcs_path(wpointer, get_windows_home_directory()) < 0)
1024 return NULL;
1026 home_directory = _wcsdup(wpointer);
1028 return home_directory;
1031 int get_set_config(const char *key, const char *value, CONFIG_TYPE type)
1033 char * config_exclusive_filename = NULL;
1034 int ret;
1036 switch(type)
1038 case CONFIG_LOCAL:
1039 config_exclusive_filename = git_pathdup("config");
1040 break;
1041 case CONFIG_GLOBAL:
1042 case CONFIG_XDGGLOBAL:
1044 const char *home = get_windows_home_directory();
1045 if (home)
1047 if (type == CONFIG_GLOBAL)
1048 config_exclusive_filename = xstrdup(mkpath("%s/.gitconfig", home));
1049 else
1050 config_exclusive_filename = xstrdup(mkpath("%s/.config/git/config", home));
1053 break;
1056 if(!config_exclusive_filename)
1057 return -1;
1059 ret = git_config_set_multivar_in_file_gently(config_exclusive_filename, key, value, NULL, 0);
1060 free(config_exclusive_filename);
1061 return ret;
1064 struct mailmap_info {
1065 char *name;
1066 char *email;
1069 struct mailmap_entry {
1070 /* name and email for the simple mail-only case */
1071 char *name;
1072 char *email;
1074 /* name and email for the complex mail and name matching case */
1075 struct string_list namemap;
1078 int git_read_mailmap(GIT_MAILMAP *mailmap)
1080 struct string_list *map;
1081 int result;
1083 if (!mailmap)
1084 return -1;
1086 *mailmap = NULL;
1087 if ((map = (struct string_list *)calloc(1, sizeof(struct string_list))) == NULL)
1088 return -1;
1090 if ((result = read_mailmap(map, NULL)) != 0)
1092 clear_mailmap(map);
1093 free(map);
1094 return result;
1097 if (!map->items)
1099 clear_mailmap(map);
1100 free(map);
1102 return -1;
1105 *mailmap = map;
1106 return 0;
1109 int git_lookup_mailmap(GIT_MAILMAP mailmap, const char** email1, const char** name1, const char* email2, void* payload, const char *(*author2_cb)(void*))
1111 struct string_list *map;
1112 int imax, imin = 0;
1114 if (!mailmap)
1115 return -1;
1117 map = (struct string_list *)mailmap;
1118 imax = map->nr - 1;
1119 while (imax >= imin)
1121 int i = imin + ((imax - imin) / 2);
1122 struct string_list_item *si = (struct string_list_item *)&map->items[i];
1123 struct mailmap_entry *me = (struct mailmap_entry *)si->util;
1124 int comp = map->cmp(si->string, email2);
1126 if (!comp)
1128 if (me->namemap.nr)
1130 const char *author2 = author2_cb(payload);
1131 for (unsigned int j = 0; j < me->namemap.nr; ++j)
1133 struct string_list_item *sj = (struct string_list_item *)&me->namemap.items[j];
1134 struct mailmap_info *mi = (struct mailmap_info *)sj->util;
1136 if (!map->cmp(sj->string, author2))
1138 if (email1)
1139 *email1 = mi->email;
1140 if (name1)
1141 *name1 = mi->name;
1142 return 0;
1147 if (email1)
1148 *email1 = me->email;
1149 if (name1)
1150 *name1 = me->name;
1151 return 0;
1153 else if (comp < 0)
1154 imin = i + 1;
1155 else
1156 imax = i - 1;
1159 return -1;
1162 void git_free_mailmap(GIT_MAILMAP mailmap)
1164 if (!mailmap)
1165 return;
1167 clear_mailmap((struct string_list *)mailmap);
1168 free(mailmap);
1171 // just for regression tests
1172 int git_mkdir(const char* path)
1174 return mkdir(path, 0);