Fix compilation warnings of gitdll.c
[TortoiseGit.git] / ext / gitdll / gitdll.c
blobef7a99a64ab355ddf697a6cfeba8e7aeda6af598
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013 - 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 "git-compat-util.h"
24 #include "msvc.h"
25 #include "gitdll.h"
26 #include "cache.h"
27 #include "commit.h"
28 #include "diff.h"
29 #include "revision.h"
30 #include "diffcore.h"
31 #include "dir.h"
32 #include "builtin.h"
33 #include "exec_cmd.h"
34 #include "cache.h"
35 #include "quote.h"
36 #include "run-command.h"
37 #include "mailmap.h"
39 #if 0
41 // This is an example of an exported variable
42 GITDLL_API int ngitdll=0;
44 // This is an example of an exported function.
45 GITDLL_API int fngitdll(void)
47 return 42;
50 // This is the constructor of a class that has been exported.
51 // see gitdll.h for the class definition
52 Cgitdll::Cgitdll()
54 return;
56 #endif
58 extern char g_last_error[];
59 const char * g_prefix;
61 char * get_git_last_error()
63 return g_last_error;
66 extern void die_dll(const char *err, va_list params);
68 void dll_entry()
70 set_die_routine(die_dll);
73 int git_get_sha1(const char *name, GIT_HASH sha1)
75 return get_sha1(name,sha1);
78 static int convert_slash(char * path)
80 while(*path)
82 if(*path == '\\' )
83 *path = '/';
84 path++;
86 return 0;
89 int git_init()
91 char path[MAX_PATH+1];
92 int ret;
93 size_t homesize;
95 _fmode = _O_BINARY;
96 _setmode(_fileno(stdin), _O_BINARY);
97 _setmode(_fileno(stdout), _O_BINARY);
98 _setmode(_fileno(stderr), _O_BINARY);
100 // set HOME if not set already
101 getenv_s(&homesize, NULL, 0, "HOME");
102 if (!homesize)
104 _wputenv_s(L"HOME", wget_windows_home_directory());
106 GetModuleFileName(NULL, path, MAX_PATH);
107 convert_slash(path);
109 git_extract_argv0_path(path);
110 g_prefix = setup_git_directory();
111 ret = git_config(git_default_config, NULL);
113 if (!homesize)
115 _putenv_s("HOME","");/* clear home evironment to avoid affact third part software*/
118 return ret;
121 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR *author, char *pbuff)
123 char *end;
125 author->Name=pbuff;
126 end=strchr(pbuff,'<');
127 if( end == 0)
129 return -1;
131 author->NameSize = end - pbuff - 1;
133 pbuff = end +1;
134 end = strchr(pbuff, '>');
135 if( end == 0)
136 return -1;
138 author->Email = pbuff ;
139 author->EmailSize = end - pbuff;
141 pbuff = end + 2;
143 author->Date = atol(pbuff);
144 end = strchr(pbuff, ' ');
145 if( end == 0 )
146 return -1;
148 pbuff=end;
149 author->TimeZone = atol(pbuff);
151 return 0;
154 int git_parse_commit(GIT_COMMIT *commit)
156 int ret = 0;
157 char *pbuf;
158 char *end;
159 struct commit *p;
161 p= (struct commit *)commit->m_pGitCommit;
163 memcpy(commit->m_hash,p->object.sha1,GIT_HASH_SIZE);
165 commit->m_Encode = NULL;
166 commit->m_EncodeSize = 0;
168 if(p->buffer == NULL)
169 return -1;
171 pbuf = p->buffer;
172 while(pbuf)
174 if (strncmp(pbuf, "author", 6) == 0)
176 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
177 if(ret)
178 return ret;
180 else if (strncmp(pbuf, "committer", 9) == 0)
182 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
183 if(ret)
184 return ret;
186 pbuf = strchr(pbuf,'\n');
187 if(pbuf == NULL)
188 return -1;
190 else if (strncmp(pbuf, "encoding", 8) == 0)
192 pbuf += 9;
193 commit->m_Encode=pbuf;
194 end = strchr(pbuf,'\n');
195 commit->m_EncodeSize=end -pbuf;
198 // the headers end after the first empty line
199 else if (*pbuf == '\n')
201 pbuf++;
203 commit->m_Subject=pbuf;
204 end = strchr(pbuf,'\n');
205 if( end == 0)
206 commit->m_SubjectSize = strlen(pbuf);
207 else
209 commit->m_SubjectSize = end - pbuf;
210 pbuf = end +1;
211 commit->m_Body = pbuf;
212 commit->m_BodySize = strlen(pbuf);
213 return 0;
217 pbuf = strchr(pbuf,'\n');
218 if(pbuf)
219 pbuf ++;
221 return 0;
224 int git_get_commit_from_hash(GIT_COMMIT *commit, GIT_HASH hash)
226 int ret = 0;
228 struct commit *p;
230 memset(commit,0,sizeof(GIT_COMMIT));
232 commit->m_pGitCommit = p = lookup_commit(hash);
234 if(commit == NULL)
235 return -1;
237 if(p == NULL)
238 return -1;
240 ret = parse_commit(p);
241 if( ret )
242 return ret;
244 return git_parse_commit(commit);
247 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
249 struct commit *p = commit->m_pGitCommit;
251 if(list == NULL)
252 return -1;
254 *list = (GIT_COMMIT_LIST*)p->parents;
255 return 0;
257 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
259 struct commit_list *l = *(struct commit_list **)list;
260 if(list == NULL || l==NULL)
261 return -1;
263 if(hash)
264 memcpy(hash, l->item->object.sha1, GIT_HASH_SIZE);
266 *list = (GIT_COMMIT_LIST *)l->next;
267 return 0;
272 int git_free_commit(GIT_COMMIT *commit)
274 struct commit *p = commit->m_pGitCommit;
276 if( p->parents)
277 free_commit_list(p->parents);
279 if( p->buffer )
281 free(p->buffer);
282 p->buffer=NULL;
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)
363 ob->flags=0;
366 if(arg != NULL)
367 argv = strtoargv(arg,&argc);
369 p_Rev = malloc(sizeof(struct rev_info));
370 memset(p_Rev,0,sizeof(struct rev_info));
372 if(p_Rev == NULL)
373 return -1;
375 invalidate_ref_cache(NULL);
377 init_revisions(p_Rev, g_prefix);
378 p_Rev->diff = 1;
380 memset(&opt, 0, sizeof(opt));
381 opt.def = "HEAD";
383 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
385 p_Rev->pPrivate = argv;
386 *handle = p_Rev;
387 return 0;
390 int git_get_log_firstcommit(GIT_LOG handle)
392 return prepare_revision_walk(handle);
395 int git_get_log_estimate_commit_count(GIT_LOG handle)
397 struct rev_info *p_Rev;
398 p_Rev=(struct rev_info *)handle;
400 return estimate_commit_count(p_Rev, p_Rev->commits);
403 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
405 int ret =0;
407 if(commit == NULL)
408 return -1;
410 memset(commit, 0, sizeof(GIT_COMMIT));
412 commit->m_pGitCommit = get_revision(handle);
413 if( commit->m_pGitCommit == NULL)
414 return -2;
416 if (follow && !log_tree_commit(handle, commit->m_pGitCommit))
418 commit->m_ignore = 1;
419 return 0;
421 commit->m_ignore = 0;
423 ret=git_parse_commit(commit);
424 if(ret)
425 return ret;
427 return 0;
430 struct notes_tree **display_notes_trees;
431 int git_close_log(GIT_LOG handle)
433 if(handle)
435 struct rev_info *p_Rev;
436 p_Rev=(struct rev_info *)handle;
437 if(p_Rev->pPrivate)
438 free(p_Rev->pPrivate);
439 free(handle);
441 free_all_pack();
443 if (display_notes_trees)
444 free_notes(*display_notes_trees);
445 display_notes_trees = 0;
446 return 0;
449 int git_open_diff(GIT_DIFF *diff, char * arg)
451 struct rev_info *p_Rev;
452 char ** argv=0;
453 int argc=0;
455 if(arg != NULL)
456 argv = strtoargv(arg,&argc);
458 p_Rev = malloc(sizeof(struct rev_info));
459 memset(p_Rev,0,sizeof(struct rev_info));
461 p_Rev->pPrivate = argv;
462 *diff = (GIT_DIFF)p_Rev;
464 init_revisions(p_Rev, g_prefix);
465 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
466 p_Rev->abbrev = 0;
467 p_Rev->diff = 1;
468 argc = setup_revisions(argc, argv, p_Rev, NULL);
470 return 0;
472 int git_close_diff(GIT_DIFF handle)
474 git_diff_flush(handle);
475 if(handle)
477 struct rev_info *p_Rev;
478 p_Rev=(struct rev_info *)handle;
479 if(p_Rev->pPrivate)
480 free(p_Rev->pPrivate);
481 free(handle);
483 return 0;
485 int git_diff_flush(GIT_DIFF diff)
487 struct diff_queue_struct *q = &diff_queued_diff;
488 struct rev_info *p_Rev;
489 int i;
490 p_Rev = (struct rev_info *)diff;
492 if(q->nr == 0)
493 return 0;
495 for (i = 0; i < q->nr; i++)
496 diff_free_filepair(q->queue[i]);
498 if(q->queue)
500 free(q->queue);
501 q->queue = NULL;
502 q->nr = q->alloc = 0;
505 if (p_Rev->diffopt.close_file)
506 fclose(p_Rev->diffopt.file);
508 free_diffstat_info(&p_Rev->diffstat);
509 return 0;
512 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count, int isstat)
514 int ret;
515 struct rev_info *p_Rev;
516 int i;
517 struct diff_queue_struct *q = &diff_queued_diff;
519 p_Rev = (struct rev_info *)diff;
521 ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);
523 if(ret)
524 return ret;
526 if(isstat)
528 diffcore_std(&p_Rev->diffopt);
530 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
531 for (i = 0; i < q->nr; i++) {
532 struct diff_filepair *p = q->queue[i];
533 //if (check_pair_status(p))
534 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
537 if(file)
538 *file = q;
539 if(count)
540 *count = q->nr;
542 return 0;
545 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count,int isstat)
547 struct rev_info *p_Rev;
548 int ret;
549 int i;
550 struct diff_queue_struct *q = &diff_queued_diff;
552 p_Rev = (struct rev_info *)diff;
554 ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);
555 if( ret )
557 free_all_pack();
558 return ret;
561 if(isstat)
563 diffcore_std(&p_Rev->diffopt);
564 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
565 for (i = 0; i < q->nr; i++) {
566 struct diff_filepair *p = q->queue[i];
567 //if (check_pair_status(p))
568 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
571 free_all_pack();
572 if(file)
573 *file = q;
574 if(count)
575 *count = q->nr;
576 return 0;
579 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)
581 struct diff_queue_struct *q = &diff_queued_diff;
582 struct rev_info *p_Rev;
583 p_Rev = (struct rev_info *)diff;
585 q = (struct diff_queue_struct *)file;
586 if(file == 0)
587 return -1;
588 if(i>=q->nr)
589 return -1;
591 if(newname)
592 *newname = q->queue[i]->two->path;
594 if(oldname)
595 *oldname = q->queue[i]->one->path;
597 if(status)
598 *status = q->queue[i]->status;
600 if(p_Rev->diffstat.files)
602 int j;
603 for(j=0;j<p_Rev->diffstat.nr;j++)
605 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
606 break;
608 if( j== p_Rev->diffstat.nr)
610 *IsBin=1;
611 *inc=0;
612 *dec=0;
613 return 0;
615 if(IsBin)
616 *IsBin = p_Rev->diffstat.files[j]->is_binary;
617 if(inc)
618 *inc = p_Rev->diffstat.files[j]->added;
619 if(dec)
620 *dec = p_Rev->diffstat.files[j]->deleted;
621 }else
623 *IsBin=1;
624 *inc=0;
625 *dec=0;
628 return 0;
631 int git_read_tree(GIT_HASH hash,read_tree_fn_t fn, void *context)
633 struct tree * root;
634 int ret;
635 reprepare_packed_git();
636 root = parse_tree_indirect(hash);
638 if (!root)
640 free_all_pack();
641 return -1;
643 ret = read_tree_recursive(root,NULL,NULL,0,NULL,fn,context);
644 free_all_pack();
645 return ret;
648 int git_add_exclude(const char *string, const char *base,
649 int baselen, struct exclude_list *which)
651 add_exclude(string, base, baselen, which);
652 return 0;
655 int git_create_exclude_list(EXCLUDE_LIST *which)
657 *which = malloc(sizeof(struct exclude_list));
658 memset(*which,0,sizeof(struct exclude_list));
659 return 0;
662 int git_free_exclude_list(EXCLUDE_LIST which)
664 int i=0;
665 struct exclude_list *p = (struct exclude_list *) which;
667 for(i=0; i<p->nr;i++)
669 free(p->excludes[i]);
671 free(p->excludes);
672 free(p);
673 return 0;
676 int git_check_excluded_1(const char *pathname,
677 int pathlen, const char *basename, int *dtype,
678 EXCLUDE_LIST el)
680 return excluded_from_list(pathname, pathlen, basename,dtype,el);
683 int git_get_notes(GIT_HASH hash, char **p_note)
685 struct strbuf sb;
686 size_t size;
687 strbuf_init(&sb,0);
688 format_display_notes(hash, &sb, "utf-8", 0);
689 *p_note = strbuf_detach(&sb,&size);
691 return 0;
694 struct cmd_struct {
695 const char *cmd;
696 int (*fn)(int, const char **, const char *);
697 int option;
700 #define RUN_SETUP (1<<0)
701 #define USE_PAGER (1<<1)
703 * require working tree to be present -- anything uses this needs
704 * RUN_SETUP for reading from the configuration file.
706 #define NEED_WORK_TREE (1<<2)
708 const char git_usage_string[] =
709 "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
710 " [-p|--paginate|--no-pager] [--no-replace-objects]\n"
711 " [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n"
712 " [-c name=value] [--help]\n"
713 " COMMAND [ARGS]";
715 const char git_more_info_string[] =
716 "See 'git help COMMAND' for more information on a specific command.";
718 /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
719 int check_pager_config(const char *cmd)
721 UNREFERENCED_PARAMETER(cmd);
722 return 0;
726 int git_run_cmd(char *cmd, char *arg)
729 int i=0;
730 char ** argv=0;
731 int argc=0;
733 static struct cmd_struct commands[] = {
734 { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
735 { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
736 { "annotate", cmd_annotate, RUN_SETUP },
737 { "apply", cmd_apply },
738 { "archive", cmd_archive },
739 { "bisect--helper", cmd_bisect__helper, RUN_SETUP | NEED_WORK_TREE },
740 { "blame", cmd_blame, RUN_SETUP },
741 { "branch", cmd_branch, RUN_SETUP },
742 { "bundle", cmd_bundle },
743 { "cat-file", cmd_cat_file, RUN_SETUP },
744 { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
745 { "checkout-index", cmd_checkout_index,
746 RUN_SETUP | NEED_WORK_TREE},
747 { "check-ref-format", cmd_check_ref_format },
748 { "check-attr", cmd_check_attr, RUN_SETUP },
749 { "cherry", cmd_cherry, RUN_SETUP },
750 { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
751 { "clone", cmd_clone },
752 { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
753 { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
754 { "commit-tree", cmd_commit_tree, RUN_SETUP },
755 { "config", cmd_config },
756 { "count-objects", cmd_count_objects, RUN_SETUP },
757 { "describe", cmd_describe, RUN_SETUP },
758 { "diff", cmd_diff },
759 { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
760 { "diff-index", cmd_diff_index, RUN_SETUP },
761 { "diff-tree", cmd_diff_tree, RUN_SETUP },
762 { "fast-export", cmd_fast_export, RUN_SETUP },
763 { "fetch", cmd_fetch, RUN_SETUP },
764 { "fetch-pack", cmd_fetch_pack, RUN_SETUP },
765 { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
766 { "for-each-ref", cmd_for_each_ref, RUN_SETUP },
767 { "format-patch", cmd_format_patch, RUN_SETUP },
768 { "fsck", cmd_fsck, RUN_SETUP },
769 { "fsck-objects", cmd_fsck, RUN_SETUP },
770 { "gc", cmd_gc, RUN_SETUP },
771 { "get-tar-commit-id", cmd_get_tar_commit_id },
772 { "grep", cmd_grep },
773 { "hash-object", cmd_hash_object },
774 { "help", cmd_help },
775 { "index-pack", cmd_index_pack },
776 { "init", cmd_init_db },
777 { "init-db", cmd_init_db },
778 { "log", cmd_log, RUN_SETUP },
779 { "ls-files", cmd_ls_files, RUN_SETUP },
780 { "ls-tree", cmd_ls_tree, RUN_SETUP },
781 { "ls-remote", cmd_ls_remote },
782 { "mailinfo", cmd_mailinfo },
783 { "mailsplit", cmd_mailsplit },
784 { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
785 { "merge-base", cmd_merge_base, RUN_SETUP },
786 { "merge-file", cmd_merge_file },
787 { "merge-index", cmd_merge_index, RUN_SETUP },
788 { "merge-ours", cmd_merge_ours, RUN_SETUP },
789 { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
790 { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
791 { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
792 { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
793 { "merge-tree", cmd_merge_tree, RUN_SETUP },
794 { "mktag", cmd_mktag, RUN_SETUP },
795 { "mktree", cmd_mktree, RUN_SETUP },
796 { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
797 { "name-rev", cmd_name_rev, RUN_SETUP },
798 { "notes", cmd_notes, RUN_SETUP },
799 { "pack-objects", cmd_pack_objects, RUN_SETUP },
800 { "pack-redundant", cmd_pack_redundant, RUN_SETUP },
801 { "patch-id", cmd_patch_id },
802 { "peek-remote", cmd_ls_remote },
803 { "pickaxe", cmd_blame, RUN_SETUP },
804 { "prune", cmd_prune, RUN_SETUP },
805 { "prune-packed", cmd_prune_packed, RUN_SETUP },
806 { "push", cmd_push, RUN_SETUP },
807 { "read-tree", cmd_read_tree, RUN_SETUP },
808 { "receive-pack", cmd_receive_pack },
809 { "reflog", cmd_reflog, RUN_SETUP },
810 { "remote", cmd_remote, RUN_SETUP },
811 { "replace", cmd_replace, RUN_SETUP },
812 { "repo-config", cmd_config },
813 { "rerere", cmd_rerere, RUN_SETUP },
814 { "reset", cmd_reset, RUN_SETUP },
815 { "rev-list", cmd_rev_list, RUN_SETUP },
816 { "rev-parse", cmd_rev_parse },
817 { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
818 { "rm", cmd_rm, RUN_SETUP },
819 { "send-pack", cmd_send_pack, RUN_SETUP },
820 { "shortlog", cmd_shortlog, USE_PAGER },
821 { "show-branch", cmd_show_branch, RUN_SETUP },
822 { "show", cmd_show, RUN_SETUP },
823 { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
824 { "stripspace", cmd_stripspace },
825 { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
826 { "tag", cmd_tag, RUN_SETUP },
827 { "tar-tree", cmd_tar_tree },
828 { "unpack-file", cmd_unpack_file, RUN_SETUP },
829 { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
830 { "update-index", cmd_update_index, RUN_SETUP },
831 { "update-ref", cmd_update_ref, RUN_SETUP },
832 { "update-server-info", cmd_update_server_info, RUN_SETUP },
833 { "upload-archive", cmd_upload_archive },
834 { "var", cmd_var },
835 { "verify-tag", cmd_verify_tag, RUN_SETUP },
836 { "version", cmd_version },
837 { "whatchanged", cmd_whatchanged, RUN_SETUP },
838 { "write-tree", cmd_write_tree, RUN_SETUP },
839 { "verify-pack", cmd_verify_pack },
840 { "show-ref", cmd_show_ref, RUN_SETUP },
841 { "pack-refs", cmd_pack_refs, RUN_SETUP },
844 git_init();
846 for(i=0;i< sizeof(commands) / sizeof(struct cmd_struct);i++)
848 if(strcmp(cmd,commands[i].cmd)==0)
850 int ret;
851 if(arg != NULL)
852 argv = strtoargv(arg,&argc);
854 ret = commands[i].fn(argc, argv, NULL);
856 if(argv)
857 free(argv);
859 discard_cache();
860 free_all_pack();
862 return ret;
867 return -1;
870 int git_for_each_ref_in(const char * refname, each_ref_fn fn, void * data)
872 int ret;
873 invalidate_ref_cache(NULL);
874 ret = for_each_ref_in(refname, fn, data);
875 free_all_pack();
876 return ret;
879 const char *git_resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
881 invalidate_ref_cache(NULL);
882 return resolve_ref_unsafe(ref,sha1,reading, flag);
884 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
886 return for_each_reflog_ent(ref,fn,cb_data);
889 int git_deref_tag(const unsigned char *tagsha1, GIT_HASH refhash)
891 struct object *obj = NULL;
892 obj = parse_object(tagsha1);
893 if (!obj)
894 return -1;
896 if (obj->type == OBJ_TAG)
898 obj = deref_tag(obj, "", 0);
899 if (!obj)
900 return -1;
902 memcpy(refhash, obj->sha1, sizeof(GIT_HASH));
903 return 0;
906 return -1;
909 static int update_some(const unsigned char *sha1, const char *base, int baselen,
910 const char *pathname, unsigned mode, int stage, void *context)
912 struct cache_entry *ce;
913 UNREFERENCED_PARAMETER(stage);
915 ce = (struct cache_entry *)context;
917 if (S_ISDIR(mode))
918 return READ_TREE_RECURSIVE;
920 hashcpy(ce->sha1, sha1);
921 memcpy(ce->name, base, baselen);
922 memcpy(ce->name + baselen, pathname, strlen(pathname));
923 ce->ce_flags = create_ce_flags(strlen(pathname)+baselen, 0);
924 ce->ce_mode = create_ce_mode(mode);
926 return 0;
929 int git_checkout_file(const char *ref, const char *path, const char *outputpath)
931 struct cache_entry *ce;
932 int ret;
933 GIT_HASH sha1;
934 struct tree * root;
935 struct checkout state;
936 struct pathspec pathspec;
937 const char *match[2];
938 ret = get_sha1(ref, sha1);
939 if(ret)
940 return ret;
942 reprepare_packed_git();
943 root = parse_tree_indirect(sha1);
945 if(!root)
947 free_all_pack();
948 return -1;
951 ce = xcalloc(1, cache_entry_size(strlen(path)));
953 match[0] = path;
954 match[1] = NULL;
956 init_pathspec(&pathspec, match);
957 pathspec.items[0].use_wildcard = 0;
958 ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce);
959 free_pathspec(&pathspec);
961 if(ret)
963 free_all_pack();
964 free(ce);
965 return ret;
967 memset(&state, 0, sizeof(state));
968 state.force = 1;
969 state.refresh_cache = 0;
971 ret = write_entry(ce, outputpath, &state, 0);
972 free_all_pack();
973 free(ce);
974 return ret;
976 struct config_buf
978 char *buf;
979 const char *key;
980 size_t size;
981 int seen;
984 static int get_config(const char *key_, const char *value_, void *cb)
986 struct config_buf *buf;
987 buf=(struct config_buf*)cb;
988 if(strcmp(key_, buf->key))
989 return 0;
991 if (value_)
992 strncpy(buf->buf,value_,buf->size);
993 else
995 buf->buf[0] = 't';
996 buf->buf[1] = 'r';
997 buf->buf[2] = 'u';
998 buf->buf[3] = 'e';
999 buf->buf[4] = 0;
1001 buf->seen = 1;
1002 return 0;
1006 // wchar_t wrapper for git_etc_gitconfig()
1007 const wchar_t *wget_msysgit_etc(void)
1009 static const wchar_t *etc_gitconfig = NULL;
1010 wchar_t wpointer[MAX_PATH];
1012 if (etc_gitconfig)
1013 return etc_gitconfig;
1015 if (xutftowcs_path(wpointer, git_etc_gitconfig()) < 0)
1016 return NULL;
1018 etc_gitconfig = _wcsdup(wpointer);
1020 return etc_gitconfig;
1023 int git_get_config(const char *key, char *buffer, int size, char *git_path)
1025 char *local, *global, *globalxdg;
1026 const char *home, *system;
1027 struct config_buf buf;
1028 UNREFERENCED_PARAMETER(git_path);
1029 buf.buf=buffer;
1030 buf.size=size;
1031 buf.seen = 0;
1032 buf.key = key;
1034 home = get_windows_home_directory();
1035 if (home)
1037 global = xstrdup(mkpath("%s/.gitconfig", home));
1038 globalxdg = xstrdup(mkpath("%s/.config/git/config", home));
1040 else
1042 global = NULL;
1043 globalxdg = NULL;
1046 system = git_etc_gitconfig();
1048 local = git_pathdup("config");
1050 if ( !buf.seen)
1051 git_config_from_file(get_config, local, &buf);
1052 if (!buf.seen && global)
1053 git_config_from_file(get_config, global, &buf);
1054 if (!buf.seen && globalxdg)
1055 git_config_from_file(get_config, globalxdg, &buf);
1056 if (!buf.seen && system)
1057 git_config_from_file(get_config, system, &buf);
1059 if(local)
1060 free(local);
1061 if(global)
1062 free(global);
1063 if (globalxdg)
1064 free(globalxdg);
1066 return !buf.seen;
1069 // taken from msysgit: compat/mingw.c
1070 const char *get_windows_home_directory(void)
1072 static const char *home_directory = NULL;
1073 struct strbuf buf = STRBUF_INIT;
1075 if (home_directory)
1076 return home_directory;
1078 home_directory = getenv("HOME");
1079 if (home_directory && *home_directory)
1080 return home_directory;
1082 strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
1083 home_directory = strbuf_detach(&buf, NULL);
1085 return home_directory;
1088 // wchar_t wrapper for get_windows_home_directory()
1089 const wchar_t *wget_windows_home_directory(void)
1091 static const wchar_t *home_directory = NULL;
1092 wchar_t wpointer[MAX_PATH];
1094 if (home_directory)
1095 return home_directory;
1097 if (xutftowcs_path(wpointer, get_windows_home_directory()) < 0)
1098 return NULL;
1100 home_directory = _wcsdup(wpointer);
1102 return home_directory;
1105 int get_set_config(const char *key, char *value, CONFIG_TYPE type,char *git_path)
1107 char * config_exclusive_filename = NULL;
1108 UNREFERENCED_PARAMETER(git_path);
1109 switch(type)
1111 case CONFIG_LOCAL:
1112 config_exclusive_filename = git_pathdup("config");
1113 break;
1114 case CONFIG_GLOBAL:
1115 case CONFIG_XDGGLOBAL:
1117 const char *home = get_windows_home_directory();
1118 if (home)
1120 if (type == CONFIG_GLOBAL)
1121 config_exclusive_filename = xstrdup(mkpath("%s/.gitconfig", home));
1122 else
1123 config_exclusive_filename = xstrdup(mkpath("%s/.config/git/config", home));
1126 break;
1129 if(!config_exclusive_filename)
1130 return -1;
1132 return git_config_set_multivar_in_file(config_exclusive_filename, key, value, NULL, 0);
1135 struct mailmap_info {
1136 char *name;
1137 char *email;
1140 struct mailmap_entry {
1141 /* name and email for the simple mail-only case */
1142 char *name;
1143 char *email;
1145 /* name and email for the complex mail and name matching case */
1146 struct string_list namemap;
1149 int git_read_mailmap(GIT_MAILMAP *mailmap)
1151 struct string_list *map;
1152 int result;
1154 if (!mailmap)
1155 return -1;
1157 *mailmap = NULL;
1158 if ((map = (struct string_list *)calloc(1, sizeof(struct string_list))) == NULL)
1159 return -1;
1161 if ((result = read_mailmap(map, NULL)) != 0)
1162 return result;
1164 *mailmap = map;
1165 return 0;
1168 const char * git_get_mailmap_author(GIT_MAILMAP mailmap, const char *email2, void *payload, const char *(*author2_cb)(void *))
1170 struct string_list *map;
1171 int imax, imin = 0;
1173 if (!mailmap)
1174 return NULL;
1176 map = (struct string_list *)mailmap;
1177 imax = map->nr - 1;
1178 while (imax >= imin)
1180 int i = imin + ((imax - imin) / 2);
1181 struct string_list_item *si = (struct string_list_item *)&map->items[i];
1182 struct mailmap_entry *me = (struct mailmap_entry *)si->util;
1183 int comp = strcmp(si->string, email2);
1185 if (!comp)
1187 if (me->namemap.nr)
1189 const char *author2 = author2_cb(payload);
1190 unsigned int j;
1191 for (j = 0; j < me->namemap.nr; ++j)
1193 struct string_list_item *sj = (struct string_list_item *)&me->namemap.items[j];
1194 struct mailmap_info *mi = (struct mailmap_info *)sj->util;
1196 if (!strcmp(sj->string, author2))
1197 return mi->name;
1201 return me->name;
1203 else if (comp < 0)
1204 imin = i + 1;
1205 else
1206 imax = i - 1;
1209 return NULL;
1212 void git_clear_mailmap(GIT_MAILMAP mailmap)
1214 if (!mailmap)
1215 return;
1217 clear_mailmap((struct string_list *)mailmap);