Constify parameter
[TortoiseGit.git] / ext / gitdll / gitdll.c
blobe48174d12bccf4bea2a3061908616556381b894e
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2016 - 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 g_prefix = setup_git_directory();
108 git_config(git_default_config, NULL);
110 return 0;
113 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR* author, const char* pbuff)
115 const char* end;
117 author->Name=pbuff;
118 end=strchr(pbuff,'<');
119 if( end == 0)
121 return -1;
123 author->NameSize = (int)(end - pbuff - 1);
125 pbuff = end +1;
126 end = strchr(pbuff, '>');
127 if( end == 0)
128 return -1;
130 author->Email = pbuff ;
131 author->EmailSize = (int)(end - pbuff);
133 pbuff = end + 2;
135 author->Date = atol(pbuff);
136 end = strchr(pbuff, ' ');
137 if( end == 0 )
138 return -1;
140 pbuff=end;
141 author->TimeZone = atol(pbuff);
143 return 0;
146 int git_parse_commit(GIT_COMMIT *commit)
148 int ret = 0;
149 const char* pbuf;
150 const char* end;
151 struct commit *p;
153 p= (struct commit *)commit->m_pGitCommit;
155 memcpy(commit->m_hash, p->object.oid.hash, GIT_HASH_SIZE);
157 commit->m_Encode = NULL;
158 commit->m_EncodeSize = 0;
160 commit->buffer = detach_commit_buffer(commit->m_pGitCommit, NULL);
162 pbuf = commit->buffer;
163 while(pbuf)
165 if (strncmp(pbuf, "author", 6) == 0)
167 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
168 if(ret)
169 return -4;
171 else if (strncmp(pbuf, "committer", 9) == 0)
173 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
174 if(ret)
175 return -5;
177 pbuf = strchr(pbuf,'\n');
178 if(pbuf == NULL)
179 return -6;
181 else if (strncmp(pbuf, "encoding", 8) == 0)
183 pbuf += 9;
184 commit->m_Encode=pbuf;
185 end = strchr(pbuf,'\n');
186 commit->m_EncodeSize= (int)(end -pbuf);
189 // the headers end after the first empty line
190 else if (*pbuf == '\n')
192 pbuf++;
194 commit->m_Subject=pbuf;
195 end = strchr(pbuf,'\n');
196 if( end == 0)
197 commit->m_SubjectSize = (int)strlen(pbuf);
198 else
200 commit->m_SubjectSize = (int)(end - pbuf);
201 pbuf = end +1;
202 commit->m_Body = pbuf;
203 commit->m_BodySize = (int)strlen(pbuf);
204 return 0;
208 pbuf = strchr(pbuf,'\n');
209 if(pbuf)
210 pbuf ++;
212 return 0;
215 int git_get_commit_from_hash(GIT_COMMIT* commit, const GIT_HASH hash)
217 int ret = 0;
219 struct commit *p;
221 if (commit == NULL)
222 return -1;
224 memset(commit,0,sizeof(GIT_COMMIT));
226 commit->m_pGitCommit = p = lookup_commit(hash);
228 if(p == NULL)
229 return -1;
231 ret = parse_commit(p);
232 if( ret )
233 return ret;
235 return git_parse_commit(commit);
238 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
240 struct commit *p = commit->m_pGitCommit;
242 if(list == NULL)
243 return -1;
245 *list = (GIT_COMMIT_LIST*)p->parents;
246 return 0;
248 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
250 struct commit_list *l;
251 if (list == NULL)
252 return -1;
254 l = *(struct commit_list **)list;
255 if (l == NULL)
256 return -1;
258 if(hash)
259 memcpy(hash, l->item->object.oid.hash, GIT_HASH_SIZE);
261 *list = (GIT_COMMIT_LIST *)l->next;
262 return 0;
267 int git_free_commit(GIT_COMMIT *commit)
269 struct commit *p = commit->m_pGitCommit;
271 if( p->parents)
272 free_commit_list(p->parents);
274 if (p->tree)
275 free_tree_buffer(p->tree);
277 #pragma warning(push)
278 #pragma warning(disable: 4090)
279 if (commit->buffer)
280 free(commit->buffer);
281 #pragma warning(pop)
283 p->object.parsed = 0;
284 p->parents = 0;
285 p->tree = 0;
287 memset(commit,0,sizeof(GIT_COMMIT));
288 return 0;
291 char **strtoargv(char *arg, int *size)
293 int count=0;
294 char *p=arg;
295 char **argv;
297 int i=0;
298 while(*p)
300 if(*p == '\\')
301 *p='/';
302 p++;
304 p=arg;
306 while(*p)
308 if(*p == ' ')
309 count ++;
310 p++;
313 argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));
314 p=(char*)(argv+count+2);
316 while(*arg)
318 if(*arg != ' ')
320 char space=' ';
321 argv[i]=p;
323 while(*arg)
325 if(*arg == '"')
327 arg++;
328 if(space == ' ')
329 space = '"';
330 else
331 space = ' ';
333 if((*arg == space) || (*arg == 0))
334 break;
336 *p++ = *arg++;
338 i++;
339 *p++=0;
341 if(*arg == 0)
342 break;
343 arg++;
345 argv[i]=NULL;
346 *size = i;
347 return argv;
349 int git_open_log(GIT_LOG * handle, char * arg)
351 struct rev_info *p_Rev;
352 char ** argv=0;
353 int argc=0;
354 unsigned int i=0;
355 struct setup_revision_opt opt;
357 /* clear flags */
358 unsigned int obj_size = get_max_object_index();
359 for(i =0; i<obj_size; i++)
361 struct object *ob= get_indexed_object(i);
362 if(ob)
364 ob->flags=0;
365 if (ob->parsed && ob->type == OBJ_COMMIT)
367 struct commit* commit = (struct commit*)ob;
368 free_commit_list(commit->parents);
369 commit->parents = NULL;
370 if (commit->tree)
371 free_tree_buffer(commit->tree);
372 commit->tree = NULL;
373 ob->parsed = 0;
378 if(arg != NULL)
379 argv = strtoargv(arg,&argc);
381 if (!argv)
382 return -1;
384 p_Rev = malloc(sizeof(struct rev_info));
385 if (p_Rev == NULL)
387 free(argv);
388 return -1;
391 memset(p_Rev,0,sizeof(struct rev_info));
393 invalidate_ref_cache(NULL);
395 init_revisions(p_Rev, g_prefix);
396 p_Rev->diff = 1;
398 memset(&opt, 0, sizeof(opt));
399 opt.def = "HEAD";
401 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
403 p_Rev->pPrivate = argv;
404 *handle = p_Rev;
405 return 0;
408 int git_get_log_firstcommit(GIT_LOG handle)
410 return prepare_revision_walk(handle);
413 int git_get_log_estimate_commit_count(GIT_LOG handle)
415 struct rev_info *p_Rev;
416 p_Rev=(struct rev_info *)handle;
418 return estimate_commit_count(p_Rev, p_Rev->commits);
421 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
423 int ret =0;
425 if(commit == NULL)
426 return -1;
428 memset(commit, 0, sizeof(GIT_COMMIT));
430 commit->m_pGitCommit = get_revision(handle);
431 if( commit->m_pGitCommit == NULL)
432 return -2;
434 if (follow && !log_tree_commit(handle, commit->m_pGitCommit))
436 commit->m_ignore = 1;
437 return 0;
439 commit->m_ignore = 0;
441 ret=git_parse_commit(commit);
442 if(ret)
443 return ret;
445 return 0;
448 struct notes_tree **display_notes_trees;
449 int git_close_log(GIT_LOG handle)
451 if(handle)
453 struct rev_info *p_Rev;
454 p_Rev=(struct rev_info *)handle;
455 if(p_Rev->pPrivate)
456 free(p_Rev->pPrivate);
457 free(handle);
459 free_all_pack();
461 if (display_notes_trees)
462 free_notes(*display_notes_trees);
463 display_notes_trees = 0;
464 return 0;
467 int git_open_diff(GIT_DIFF *diff, char * arg)
469 struct rev_info *p_Rev;
470 char ** argv=0;
471 int argc=0;
473 if(arg != NULL)
474 argv = strtoargv(arg,&argc);
476 p_Rev = malloc(sizeof(struct rev_info));
477 memset(p_Rev,0,sizeof(struct rev_info));
479 p_Rev->pPrivate = argv;
480 *diff = (GIT_DIFF)p_Rev;
482 init_revisions(p_Rev, g_prefix);
483 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
484 p_Rev->abbrev = 0;
485 p_Rev->diff = 1;
486 argc = setup_revisions(argc, argv, p_Rev, NULL);
488 return 0;
490 int git_close_diff(GIT_DIFF handle)
492 git_diff_flush(handle);
493 if(handle)
495 struct rev_info *p_Rev;
496 p_Rev=(struct rev_info *)handle;
497 if(p_Rev->pPrivate)
498 free(p_Rev->pPrivate);
499 free(handle);
501 return 0;
503 int git_diff_flush(GIT_DIFF diff)
505 struct diff_queue_struct *q = &diff_queued_diff;
506 struct rev_info *p_Rev;
507 int i;
508 p_Rev = (struct rev_info *)diff;
510 if(q->nr == 0)
511 return 0;
513 for (i = 0; i < q->nr; i++)
514 diff_free_filepair(q->queue[i]);
516 if(q->queue)
518 free(q->queue);
519 q->queue = NULL;
520 q->nr = q->alloc = 0;
523 if (p_Rev->diffopt.close_file)
524 fclose(p_Rev->diffopt.file);
526 free_diffstat_info(&p_Rev->diffstat);
527 return 0;
530 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count, int isstat)
532 int ret;
533 struct rev_info *p_Rev;
534 int i;
535 struct diff_queue_struct *q = &diff_queued_diff;
537 p_Rev = (struct rev_info *)diff;
539 ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);
541 if(ret)
542 return ret;
544 if(isstat)
546 diffcore_std(&p_Rev->diffopt);
548 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
549 for (i = 0; i < q->nr; i++) {
550 struct diff_filepair *p = q->queue[i];
551 //if (check_pair_status(p))
552 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
555 if(file)
556 *file = q;
557 if(count)
558 *count = q->nr;
560 return 0;
563 int git_do_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count,int isstat)
565 struct rev_info *p_Rev;
566 int ret;
567 int i;
568 struct diff_queue_struct *q = &diff_queued_diff;
570 p_Rev = (struct rev_info *)diff;
572 ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);
573 if( ret )
575 free_all_pack();
576 return ret;
579 if(isstat)
581 diffcore_std(&p_Rev->diffopt);
582 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
583 for (i = 0; i < q->nr; i++) {
584 struct diff_filepair *p = q->queue[i];
585 //if (check_pair_status(p))
586 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
589 free_all_pack();
590 if(file)
591 *file = q;
592 if(count)
593 *count = q->nr;
594 return 0;
597 int git_get_diff_file(GIT_DIFF diff,GIT_FILE file,int i, char **newname, char ** oldname, int *status, int *IsBin, int *inc, int *dec)
599 struct diff_queue_struct *q = &diff_queued_diff;
600 struct rev_info *p_Rev;
601 p_Rev = (struct rev_info *)diff;
603 q = (struct diff_queue_struct *)file;
604 if(file == 0)
605 return -1;
606 if(i>=q->nr)
607 return -1;
609 assert(newname && oldname && status);
611 *newname = q->queue[i]->two->path;
612 *oldname = q->queue[i]->one->path;
613 *status = q->queue[i]->status;
615 if(p_Rev->diffstat.files)
617 int j;
618 for(j=0;j<p_Rev->diffstat.nr;j++)
620 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
621 break;
623 if( j== p_Rev->diffstat.nr)
625 *IsBin=1;
626 *inc=0;
627 *dec=0;
628 return 0;
630 if(IsBin)
631 *IsBin = p_Rev->diffstat.files[j]->is_binary;
632 if(inc)
633 *inc = (int)p_Rev->diffstat.files[j]->added;
634 if(dec)
635 *dec = (int)p_Rev->diffstat.files[j]->deleted;
636 }else
638 *IsBin=1;
639 *inc=0;
640 *dec=0;
643 return 0;
646 int git_add_exclude(const char *string, const char *base,
647 int baselen, struct exclude_list *which, int lineno)
649 add_exclude(string, base, baselen, which, lineno);
650 return 0;
653 int git_create_exclude_list(EXCLUDE_LIST *which)
655 *which = malloc(sizeof(struct exclude_list));
656 memset(*which,0,sizeof(struct exclude_list));
657 return 0;
660 int git_free_exclude_list(EXCLUDE_LIST which)
662 int i=0;
663 struct exclude_list *p = (struct exclude_list *) which;
665 for(i=0; i<p->nr;i++)
667 free(p->excludes[i]);
669 free(p->excludes);
670 free(p);
671 return 0;
674 int git_check_excluded_1(const char *pathname,
675 int pathlen, const char *basename, int *dtype,
676 EXCLUDE_LIST el)
678 return is_excluded_from_list(pathname, pathlen, basename, dtype, el);
681 int git_get_notes(const GIT_HASH hash, char** p_note)
683 struct strbuf sb;
684 size_t size;
685 strbuf_init(&sb,0);
686 format_display_notes(hash, &sb, "utf-8", 1);
687 *p_note = strbuf_detach(&sb,&size);
689 return 0;
692 struct cmd_struct {
693 const char *cmd;
694 int (*fn)(int, const char **, const char *);
695 int option;
698 #define RUN_SETUP (1<<0)
700 static struct cmd_struct commands[] = {
701 { "notes", cmd_notes, RUN_SETUP },
702 { "update-index", cmd_update_index, RUN_SETUP },
705 int git_run_cmd(char *cmd, char *arg)
708 int i=0;
709 char ** argv=0;
710 int argc=0;
712 git_init();
714 for(i=0;i< sizeof(commands) / sizeof(struct cmd_struct);i++)
716 if(strcmp(cmd,commands[i].cmd)==0)
718 int ret;
719 if(arg != NULL)
720 argv = strtoargv(arg,&argc);
722 ret = commands[i].fn(argc, argv, NULL);
724 if(argv)
725 free(argv);
727 discard_cache();
728 free_all_pack();
730 return ret;
735 return -1;
738 void git_exit_cleanup(void)
740 git_atexit_dispatch();
741 git_atexit_clear();
744 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
746 return for_each_reflog_ent(ref,fn,cb_data);
749 static int update_some(const unsigned char* sha1, struct strbuf* base,
750 const char *pathname, unsigned mode, int stage, void *context)
752 struct cache_entry *ce;
753 UNREFERENCED_PARAMETER(stage);
755 ce = (struct cache_entry *)context;
757 if (S_ISDIR(mode))
758 return READ_TREE_RECURSIVE;
760 hashcpy(ce->sha1, sha1);
761 memcpy(ce->name, base->buf, base->len);
762 memcpy(ce->name + base->len, pathname, strlen(pathname));
763 ce->ce_flags = create_ce_flags((unsigned int)(strlen(pathname) + base->len));
764 ce->ce_mode = create_ce_mode(mode);
766 return 0;
769 int git_checkout_file(const char* ref, const char* path, char* outputpath)
771 struct cache_entry *ce;
772 int ret;
773 GIT_HASH sha1;
774 struct tree * root;
775 struct checkout state;
776 struct pathspec pathspec;
777 const char *matchbuf[1];
778 ret = get_sha1(ref, sha1);
779 if(ret)
780 return ret;
782 reprepare_packed_git();
783 root = parse_tree_indirect(sha1);
785 if(!root)
787 free_all_pack();
788 return -1;
791 ce = xcalloc(1, cache_entry_size(strlen(path)));
793 matchbuf[0] = NULL;
794 parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC, PATHSPEC_PREFER_CWD, path, matchbuf);
795 pathspec.items[0].nowildcard_len = pathspec.items[0].len;
796 ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce);
797 clear_pathspec(&pathspec);
799 if(ret)
801 free_all_pack();
802 free(ce);
803 return ret;
805 memset(&state, 0, sizeof(state));
806 state.force = 1;
807 state.refresh_cache = 0;
809 ret = write_entry(ce, outputpath, &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 strncpy(buf->buf,value_,buf->size);
831 else
833 buf->buf[0] = 't';
834 buf->buf[1] = 'r';
835 buf->buf[2] = 'u';
836 buf->buf[3] = 'e';
837 buf->buf[4] = 0;
839 buf->seen = 1;
840 return 0;
844 // wchar_t wrapper for program_data_config()
845 const wchar_t* wget_program_data_config(void)
847 static const wchar_t *programdata_git_config = NULL;
848 wchar_t wpointer[MAX_PATH];
850 if (programdata_git_config)
851 return programdata_git_config;
853 if (xutftowcs_path(wpointer, program_data_config()) < 0)
854 return NULL;
856 programdata_git_config = _wcsdup(wpointer);
858 return programdata_git_config;
861 // wchar_t wrapper for git_etc_gitconfig()
862 const wchar_t *wget_msysgit_etc(void)
864 static const wchar_t *etc_gitconfig = NULL;
865 wchar_t wpointer[MAX_PATH];
867 if (etc_gitconfig)
868 return etc_gitconfig;
870 if (xutftowcs_path(wpointer, git_etc_gitconfig()) < 0)
871 return NULL;
873 etc_gitconfig = _wcsdup(wpointer);
875 return etc_gitconfig;
878 int git_get_config(const char *key, char *buffer, int size)
880 char *local, *global, *globalxdg;
881 const char *home, *system, *programdata;
882 struct config_buf buf;
883 struct git_config_source config_source = { 0 };
885 buf.buf=buffer;
886 buf.size=size;
887 buf.seen = 0;
888 buf.key = key;
890 home = get_windows_home_directory();
891 if (home)
893 global = xstrdup(mkpath("%s/.gitconfig", home));
894 globalxdg = xstrdup(mkpath("%s/.config/git/config", home));
896 else
898 global = NULL;
899 globalxdg = NULL;
902 system = git_etc_gitconfig();
903 programdata = git_program_data_config();
905 local = git_pathdup("config");
907 if (!buf.seen)
909 config_source.file = local;
910 git_config_with_options(get_config, &buf, &config_source, 1);
912 if (!buf.seen && global)
914 config_source.file = global;
915 git_config_with_options(get_config, &buf, &config_source, 1);
917 if (!buf.seen && globalxdg)
919 config_source.file = globalxdg;
920 git_config_with_options(get_config, &buf, &config_source, 1);
922 if (!buf.seen && system)
924 config_source.file = system;
925 git_config_with_options(get_config, &buf, &config_source, 1);
927 if (!buf.seen && programdata)
929 config_source.file = programdata;
930 git_config_with_options(get_config, &buf, &config_source, 1);
933 if(local)
934 free(local);
935 if(global)
936 free(global);
937 if (globalxdg)
938 free(globalxdg);
940 return !buf.seen;
943 // taken from msysgit: compat/mingw.c
944 const char *get_windows_home_directory(void)
946 static const char *home_directory = NULL;
947 struct strbuf buf = STRBUF_INIT;
949 if (home_directory)
950 return home_directory;
952 home_directory = getenv("HOME");
953 if (home_directory && *home_directory)
955 home_directory = _strdup(home_directory);
956 return home_directory;
959 strbuf_addf(&buf, "%s%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
960 home_directory = strbuf_detach(&buf, NULL);
962 return home_directory;
965 // wchar_t wrapper for get_windows_home_directory()
966 const wchar_t *wget_windows_home_directory(void)
968 static const wchar_t *home_directory = NULL;
969 wchar_t wpointer[MAX_PATH];
971 if (home_directory)
972 return home_directory;
974 if (xutftowcs_path(wpointer, get_windows_home_directory()) < 0)
975 return NULL;
977 home_directory = _wcsdup(wpointer);
979 return home_directory;
982 int get_set_config(const char *key, const char *value, CONFIG_TYPE type)
984 char * config_exclusive_filename = NULL;
985 int ret;
987 switch(type)
989 case CONFIG_LOCAL:
990 config_exclusive_filename = git_pathdup("config");
991 break;
992 case CONFIG_GLOBAL:
993 case CONFIG_XDGGLOBAL:
995 const char *home = get_windows_home_directory();
996 if (home)
998 if (type == CONFIG_GLOBAL)
999 config_exclusive_filename = xstrdup(mkpath("%s/.gitconfig", home));
1000 else
1001 config_exclusive_filename = xstrdup(mkpath("%s/.config/git/config", home));
1004 break;
1007 if(!config_exclusive_filename)
1008 return -1;
1010 ret = git_config_set_multivar_in_file_gently(config_exclusive_filename, key, value, NULL, 0);
1011 free(config_exclusive_filename);
1012 return ret;
1015 struct mailmap_info {
1016 char *name;
1017 char *email;
1020 struct mailmap_entry {
1021 /* name and email for the simple mail-only case */
1022 char *name;
1023 char *email;
1025 /* name and email for the complex mail and name matching case */
1026 struct string_list namemap;
1029 int git_read_mailmap(GIT_MAILMAP *mailmap)
1031 struct string_list *map;
1032 int result;
1034 if (!mailmap)
1035 return -1;
1037 *mailmap = NULL;
1038 if ((map = (struct string_list *)calloc(1, sizeof(struct string_list))) == NULL)
1039 return -1;
1041 if ((result = read_mailmap(map, NULL)) != 0)
1043 clear_mailmap(map);
1044 free(map);
1045 return result;
1048 if (!map->items)
1050 clear_mailmap(map);
1051 free(map);
1053 return -1;
1056 *mailmap = map;
1057 return 0;
1060 int git_lookup_mailmap(GIT_MAILMAP mailmap, const char** email1, const char** name1, const char* email2, void* payload, const char *(*author2_cb)(void*))
1062 struct string_list *map;
1063 int imax, imin = 0;
1065 if (!mailmap)
1066 return -1;
1068 map = (struct string_list *)mailmap;
1069 imax = map->nr - 1;
1070 while (imax >= imin)
1072 int i = imin + ((imax - imin) / 2);
1073 struct string_list_item *si = (struct string_list_item *)&map->items[i];
1074 struct mailmap_entry *me = (struct mailmap_entry *)si->util;
1075 int comp = map->cmp(si->string, email2);
1077 if (!comp)
1079 if (me->namemap.nr)
1081 const char *author2 = author2_cb(payload);
1082 unsigned int j;
1083 for (j = 0; j < me->namemap.nr; ++j)
1085 struct string_list_item *sj = (struct string_list_item *)&me->namemap.items[j];
1086 struct mailmap_info *mi = (struct mailmap_info *)sj->util;
1088 if (!map->cmp(sj->string, author2))
1090 if (email1)
1091 *email1 = mi->email;
1092 if (name1)
1093 *name1 = mi->name;
1094 return 0;
1099 if (email1)
1100 *email1 = me->email;
1101 if (name1)
1102 *name1 = me->name;
1103 return 0;
1105 else if (comp < 0)
1106 imin = i + 1;
1107 else
1108 imax = i - 1;
1111 return -1;
1114 void git_free_mailmap(GIT_MAILMAP mailmap)
1116 if (!mailmap)
1117 return;
1119 clear_mailmap((struct string_list *)mailmap);
1120 free(mailmap);