Make TortoiseGit work with unicode HomeDirectories
[TortoiseGit.git] / ext / gitdll / gitdll.c
blob61d2137a7abebbaa7a3bc9631dc866dac911f324
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2012 - 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"
38 const char git_version_string[] = GIT_VERSION;
41 #if 0
43 // This is an example of an exported variable
44 GITDLL_API int ngitdll=0;
46 // This is an example of an exported function.
47 GITDLL_API int fngitdll(void)
49 return 42;
52 // This is the constructor of a class that has been exported.
53 // see gitdll.h for the class definition
54 Cgitdll::Cgitdll()
56 return;
58 #endif
60 extern char g_last_error[];
61 void * g_prefix;
63 char * get_git_last_error()
65 return g_last_error;
68 extern void die_dll(const char *err, va_list params);
70 void dll_entry()
72 set_die_routine(die_dll);
75 int git_get_sha1(const char *name, GIT_HASH sha1)
77 return get_sha1(name,sha1);
80 static int convert_slash(char * path)
82 while(*path)
84 if(*path == '\\' )
85 *path = '/';
86 path++;
88 return 0;
91 int git_init()
93 const wchar_t *home;
94 char path[MAX_PATH+1];
95 char *prefix;
96 int ret;
97 size_t homesize;
99 _fmode = _O_BINARY;
100 _setmode(_fileno(stdin), _O_BINARY);
101 _setmode(_fileno(stdout), _O_BINARY);
102 _setmode(_fileno(stderr), _O_BINARY);
104 // set HOME if not set already
105 getenv_s(&homesize, NULL, 0, "HOME");
106 if (!homesize)
108 home = wget_windows_home_directory();
109 _wputenv_s(L"HOME",home);
111 GetModuleFileName(NULL, path, MAX_PATH);
112 convert_slash(path);
114 git_extract_argv0_path(path);
115 g_prefix = prefix = setup_git_directory();
116 ret = git_config(git_default_config, NULL);
118 if (!homesize)
120 _putenv_s("HOME","");/* clear home evironment to avoid affact third part software*/
123 return ret;
126 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR *author, char *pbuff)
128 char *end;
130 author->Name=pbuff;
131 end=strchr(pbuff,'<');
132 if( end == 0)
134 return -1;
136 author->NameSize = end - pbuff - 1;
138 pbuff = end +1;
139 end = strchr(pbuff, '>');
140 if( end == 0)
141 return -1;
143 author->Email = pbuff ;
144 author->EmailSize = end - pbuff;
146 pbuff = end + 2;
148 author->Date = atol(pbuff);
149 end = strchr(pbuff, ' ');
150 if( end == 0 )
151 return -1;
153 pbuff=end;
154 author->TimeZone = atol(pbuff);
156 return 0;
159 int git_parse_commit(GIT_COMMIT *commit)
161 int ret = 0;
162 char *pbuf;
163 char *end;
164 struct commit *p;
166 p= (struct commit *)commit->m_pGitCommit;
168 memcpy(commit->m_hash,p->object.sha1,GIT_HASH_SIZE);
170 commit->m_Encode = NULL;
171 commit->m_EncodeSize = 0;
173 if(p->buffer == NULL)
174 return -1;
176 pbuf = p->buffer;
177 while(pbuf)
179 if( strncmp(pbuf,"author",6) == 0)
181 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
182 if(ret)
183 return ret;
185 if( strncmp(pbuf, "committer",9) == 0)
187 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
188 if(ret)
189 return ret;
191 pbuf = strchr(pbuf,'\n');
192 if(pbuf == NULL)
193 return -1;
195 pbuf ++;
197 if( strncmp(pbuf, "encoding",8) == 0 )
199 pbuf += 9;
200 commit->m_Encode=pbuf;
201 end = strchr(pbuf,'\n');
202 commit->m_EncodeSize=end -pbuf;
204 pbuf = end +1;
207 while((*pbuf) && (*pbuf == '\n'))
208 pbuf ++;
210 commit->m_Subject=pbuf;
211 end = strchr(pbuf,'\n');
212 if( end == 0)
213 commit->m_SubjectSize = strlen(pbuf);
214 else
216 commit->m_SubjectSize = end - pbuf;
217 pbuf = end +1;
218 commit->m_Body = pbuf;
219 commit->m_BodySize = strlen(pbuf);
220 return 0;
225 pbuf = strchr(pbuf,'\n');
226 if(pbuf)
227 pbuf ++;
229 return 0;
232 int git_get_commit_from_hash(GIT_COMMIT *commit, GIT_HASH hash)
234 int ret = 0;
236 struct commit *p;
238 memset(commit,0,sizeof(GIT_COMMIT));
240 commit->m_pGitCommit = p = lookup_commit(hash);
242 if(commit == NULL)
243 return -1;
245 if(p == NULL)
246 return -1;
248 ret = parse_commit(p);
249 if( ret )
250 return ret;
252 return git_parse_commit(commit);
255 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
257 struct commit *p = commit->m_pGitCommit;
259 if(list == NULL)
260 return -1;
262 *list = (GIT_COMMIT_LIST*)p->parents;
263 return 0;
265 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
267 struct commit_list *l = *(struct commit_list **)list;
268 if(list == NULL || l==NULL)
269 return -1;
271 if(hash)
272 memcpy(hash, l->item->object.sha1, GIT_HASH_SIZE);
274 *list = (GIT_COMMIT_LIST *)l->next;
275 return 0;
280 int git_free_commit(GIT_COMMIT *commit)
282 struct commit *p = commit->m_pGitCommit;
284 if( p->parents)
285 free_commit_list(p->parents);
287 if( p->buffer )
289 free(p->buffer);
290 p->buffer=NULL;
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 unsigned int i=0;
363 struct setup_revision_opt opt;
365 /* clear flags */
366 unsigned int obj_size = get_max_object_index();
367 for(i =0; i<obj_size; i++)
369 struct object *ob= get_indexed_object(i);
370 if(ob)
371 ob->flags=0;
374 if(arg != NULL)
375 argv = strtoargv(arg,&argc);
377 p_Rev = malloc(sizeof(struct rev_info));
378 memset(p_Rev,0,sizeof(struct rev_info));
380 if(p_Rev == NULL)
381 return -1;
383 init_revisions(p_Rev, g_prefix);
384 p_Rev->diff = 1;
386 memset(&opt, 0, sizeof(opt));
387 opt.def = "HEAD";
389 cmd_log_init(argc, argv, g_prefix,p_Rev,&opt);
391 p_Rev->pPrivate = argv;
392 *handle = p_Rev;
393 return 0;
396 int git_get_log_firstcommit(GIT_LOG handle)
398 return prepare_revision_walk(handle);
401 int git_get_log_estimate_commit_count(GIT_LOG handle)
403 struct rev_info *p_Rev;
404 p_Rev=(struct rev_info *)handle;
406 return estimate_commit_count(p_Rev, p_Rev->commits);
409 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit, int follow)
411 int ret =0;
413 if(commit == NULL)
414 return -1;
416 memset(commit, 0, sizeof(GIT_COMMIT));
418 commit->m_pGitCommit = get_revision(handle);
419 if( commit->m_pGitCommit == NULL)
420 return -2;
422 if (follow && !log_tree_commit(handle, commit->m_pGitCommit))
424 commit->m_ignore = 1;
425 return 0;
427 commit->m_ignore = 0;
429 ret=git_parse_commit(commit);
430 if(ret)
431 return ret;
433 return 0;
436 struct notes_tree **display_notes_trees;
437 int git_close_log(GIT_LOG handle)
439 if(handle)
441 struct rev_info *p_Rev;
442 p_Rev=(struct rev_info *)handle;
443 if(p_Rev->pPrivate)
444 free(p_Rev->pPrivate);
445 free(handle);
447 free_all_pack();
449 free_notes(*display_notes_trees);
450 display_notes_trees = 0;
451 return 0;
454 int git_open_diff(GIT_DIFF *diff, char * arg)
456 struct rev_info *p_Rev;
457 char ** argv=0;
458 int argc=0;
460 if(arg != NULL)
461 argv = strtoargv(arg,&argc);
463 p_Rev = malloc(sizeof(struct rev_info));
464 memset(p_Rev,0,sizeof(struct rev_info));
466 p_Rev->pPrivate = argv;
467 *diff = (GIT_DIFF)p_Rev;
469 init_revisions(p_Rev, g_prefix);
470 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
471 p_Rev->abbrev = 0;
472 p_Rev->diff = 1;
473 argc = setup_revisions(argc, argv, p_Rev, NULL);
475 return 0;
477 int git_close_diff(GIT_DIFF handle)
479 git_diff_flush(handle);
480 if(handle)
482 struct rev_info *p_Rev;
483 p_Rev=(struct rev_info *)handle;
484 if(p_Rev->pPrivate)
485 free(p_Rev->pPrivate);
486 free(handle);
488 return 0;
490 int git_diff_flush(GIT_DIFF diff)
492 struct diff_queue_struct *q = &diff_queued_diff;
493 struct rev_info *p_Rev;
494 int i;
495 p_Rev = (struct rev_info *)diff;
497 if(q->nr == 0)
498 return 0;
500 for (i = 0; i < q->nr; i++)
501 diff_free_filepair(q->queue[i]);
503 if(q->queue)
505 free(q->queue);
506 q->queue = NULL;
507 q->nr = q->alloc = 0;
510 if (p_Rev->diffopt.close_file)
511 fclose(p_Rev->diffopt.file);
513 free_diffstat_info(&p_Rev->diffstat);
514 return 0;
517 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count, int isstat)
519 int ret;
520 struct rev_info *p_Rev;
521 int i;
522 struct diff_queue_struct *q = &diff_queued_diff;
524 p_Rev = (struct rev_info *)diff;
526 ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);
528 if(ret)
529 return ret;
531 if(isstat)
533 diffcore_std(&p_Rev->diffopt);
535 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
536 for (i = 0; i < q->nr; i++) {
537 struct diff_filepair *p = q->queue[i];
538 //if (check_pair_status(p))
539 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
542 if(file)
543 *file = q;
544 if(count)
545 *count = q->nr;
547 return 0;
550 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count,int isstat)
552 struct rev_info *p_Rev;
553 int ret;
554 int i;
555 struct diff_queue_struct *q = &diff_queued_diff;
557 p_Rev = (struct rev_info *)diff;
559 ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);
560 if( ret )
562 free_all_pack();
563 return ret;
566 if(isstat)
568 diffcore_std(&p_Rev->diffopt);
569 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
570 for (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);
576 free_all_pack();
577 if(file)
578 *file = q;
579 if(count)
580 *count = q->nr;
581 return 0;
584 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)
586 struct diff_queue_struct *q = &diff_queued_diff;
587 struct rev_info *p_Rev;
588 p_Rev = (struct rev_info *)diff;
590 q = (struct diff_queue_struct *)file;
591 if(file == 0)
592 return -1;
593 if(i>=q->nr)
594 return -1;
596 if(newname)
597 *newname = q->queue[i]->two->path;
599 if(oldname)
600 *oldname = q->queue[i]->one->path;
602 if(status)
603 *status = q->queue[i]->status;
605 if(p_Rev->diffstat.files)
607 int j;
608 for(j=0;j<p_Rev->diffstat.nr;j++)
610 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
611 break;
613 if( j== p_Rev->diffstat.nr)
615 *IsBin=1;
616 *inc=0;
617 *dec=0;
618 return 0;
620 if(IsBin)
621 *IsBin = p_Rev->diffstat.files[j]->is_binary;
622 if(inc)
623 *inc = p_Rev->diffstat.files[j]->added;
624 if(dec)
625 *dec = p_Rev->diffstat.files[j]->deleted;
626 }else
628 *IsBin=1;
629 *inc=0;
630 *dec=0;
633 return 0;
636 int git_read_tree(GIT_HASH hash,read_tree_fn_t fn, void *context)
638 struct tree * root;
639 int ret;
640 reprepare_packed_git();
641 root = parse_tree_indirect(hash);
643 if (!root)
645 free_all_pack();
646 return -1;
648 ret = read_tree_recursive(root,NULL,NULL,0,NULL,fn,context);
649 free_all_pack();
650 return ret;
653 int git_add_exclude(const char *string, const char *base,
654 int baselen, struct exclude_list *which)
656 add_exclude(string, base, baselen, which);
657 return 0;
660 int git_create_exclude_list(EXCLUDE_LIST *which)
662 *which = malloc(sizeof(struct exclude_list));
663 memset(*which,0,sizeof(struct exclude_list));
664 return 0;
667 int git_free_exclude_list(EXCLUDE_LIST which)
669 int i=0;
670 struct exclude_list *p = (struct exclude_list *) which;
672 for(i=0; i<p->nr;i++)
674 free(p->excludes[i]);
676 free(p->excludes);
677 free(p);
678 return 0;
681 int git_check_excluded_1(const char *pathname,
682 int pathlen, const char *basename, int *dtype,
683 EXCLUDE_LIST el)
685 return excluded_from_list(pathname, pathlen, basename,dtype,el);
688 int git_get_notes(GIT_HASH hash, char **p_note)
690 struct strbuf sb;
691 size_t size;
692 strbuf_init(&sb,0);
693 format_display_notes(hash, &sb, "utf-8", 0);
694 *p_note = strbuf_detach(&sb,&size);
696 return 0;
699 struct cmd_struct {
700 const char *cmd;
701 int (*fn)(int, const char **, const char *);
702 int option;
705 #define RUN_SETUP (1<<0)
706 #define USE_PAGER (1<<1)
708 * require working tree to be present -- anything uses this needs
709 * RUN_SETUP for reading from the configuration file.
711 #define NEED_WORK_TREE (1<<2)
713 const char git_usage_string[] =
714 "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
715 " [-p|--paginate|--no-pager] [--no-replace-objects]\n"
716 " [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n"
717 " [-c name=value] [--help]\n"
718 " COMMAND [ARGS]";
720 const char git_more_info_string[] =
721 "See 'git help COMMAND' for more information on a specific command.";
723 /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
724 int check_pager_config(const char *cmd)
726 return 0;
730 int git_run_cmd(char *cmd, char *arg)
733 int i=0;
734 char ** argv=0;
735 int argc=0;
737 static struct cmd_struct commands[] = {
738 { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
739 { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
740 { "annotate", cmd_annotate, RUN_SETUP },
741 { "apply", cmd_apply },
742 { "archive", cmd_archive },
743 { "bisect--helper", cmd_bisect__helper, RUN_SETUP | NEED_WORK_TREE },
744 { "blame", cmd_blame, RUN_SETUP },
745 { "branch", cmd_branch, RUN_SETUP },
746 { "bundle", cmd_bundle },
747 { "cat-file", cmd_cat_file, RUN_SETUP },
748 { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
749 { "checkout-index", cmd_checkout_index,
750 RUN_SETUP | NEED_WORK_TREE},
751 { "check-ref-format", cmd_check_ref_format },
752 { "check-attr", cmd_check_attr, RUN_SETUP },
753 { "cherry", cmd_cherry, RUN_SETUP },
754 { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
755 { "clone", cmd_clone },
756 { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
757 { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
758 { "commit-tree", cmd_commit_tree, RUN_SETUP },
759 { "config", cmd_config },
760 { "count-objects", cmd_count_objects, RUN_SETUP },
761 { "describe", cmd_describe, RUN_SETUP },
762 { "diff", cmd_diff },
763 { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
764 { "diff-index", cmd_diff_index, RUN_SETUP },
765 { "diff-tree", cmd_diff_tree, RUN_SETUP },
766 { "fast-export", cmd_fast_export, RUN_SETUP },
767 { "fetch", cmd_fetch, RUN_SETUP },
768 { "fetch-pack", cmd_fetch_pack, RUN_SETUP },
769 { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
770 { "for-each-ref", cmd_for_each_ref, RUN_SETUP },
771 { "format-patch", cmd_format_patch, RUN_SETUP },
772 { "fsck", cmd_fsck, RUN_SETUP },
773 { "fsck-objects", cmd_fsck, RUN_SETUP },
774 { "gc", cmd_gc, RUN_SETUP },
775 { "get-tar-commit-id", cmd_get_tar_commit_id },
776 { "grep", cmd_grep },
777 { "hash-object", cmd_hash_object },
778 { "help", cmd_help },
779 { "index-pack", cmd_index_pack },
780 { "init", cmd_init_db },
781 { "init-db", cmd_init_db },
782 { "log", cmd_log, RUN_SETUP },
783 { "ls-files", cmd_ls_files, RUN_SETUP },
784 { "ls-tree", cmd_ls_tree, RUN_SETUP },
785 { "ls-remote", cmd_ls_remote },
786 { "mailinfo", cmd_mailinfo },
787 { "mailsplit", cmd_mailsplit },
788 { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
789 { "merge-base", cmd_merge_base, RUN_SETUP },
790 { "merge-file", cmd_merge_file },
791 { "merge-index", cmd_merge_index, RUN_SETUP },
792 { "merge-ours", cmd_merge_ours, RUN_SETUP },
793 { "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
794 { "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
795 { "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
796 { "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
797 { "merge-tree", cmd_merge_tree, RUN_SETUP },
798 { "mktag", cmd_mktag, RUN_SETUP },
799 { "mktree", cmd_mktree, RUN_SETUP },
800 { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
801 { "name-rev", cmd_name_rev, RUN_SETUP },
802 { "notes", cmd_notes, RUN_SETUP },
803 { "pack-objects", cmd_pack_objects, RUN_SETUP },
804 { "pack-redundant", cmd_pack_redundant, RUN_SETUP },
805 { "patch-id", cmd_patch_id },
806 { "peek-remote", cmd_ls_remote },
807 { "pickaxe", cmd_blame, RUN_SETUP },
808 { "prune", cmd_prune, RUN_SETUP },
809 { "prune-packed", cmd_prune_packed, RUN_SETUP },
810 { "push", cmd_push, RUN_SETUP },
811 { "read-tree", cmd_read_tree, RUN_SETUP },
812 { "receive-pack", cmd_receive_pack },
813 { "reflog", cmd_reflog, RUN_SETUP },
814 { "remote", cmd_remote, RUN_SETUP },
815 { "replace", cmd_replace, RUN_SETUP },
816 { "repo-config", cmd_config },
817 { "rerere", cmd_rerere, RUN_SETUP },
818 { "reset", cmd_reset, RUN_SETUP },
819 { "rev-list", cmd_rev_list, RUN_SETUP },
820 { "rev-parse", cmd_rev_parse },
821 { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
822 { "rm", cmd_rm, RUN_SETUP },
823 { "send-pack", cmd_send_pack, RUN_SETUP },
824 { "shortlog", cmd_shortlog, USE_PAGER },
825 { "show-branch", cmd_show_branch, RUN_SETUP },
826 { "show", cmd_show, RUN_SETUP },
827 { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
828 { "stripspace", cmd_stripspace },
829 { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
830 { "tag", cmd_tag, RUN_SETUP },
831 { "tar-tree", cmd_tar_tree },
832 { "unpack-file", cmd_unpack_file, RUN_SETUP },
833 { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
834 { "update-index", cmd_update_index, RUN_SETUP },
835 { "update-ref", cmd_update_ref, RUN_SETUP },
836 { "update-server-info", cmd_update_server_info, RUN_SETUP },
837 { "upload-archive", cmd_upload_archive },
838 { "var", cmd_var },
839 { "verify-tag", cmd_verify_tag, RUN_SETUP },
840 { "version", cmd_version },
841 { "whatchanged", cmd_whatchanged, RUN_SETUP },
842 { "write-tree", cmd_write_tree, RUN_SETUP },
843 { "verify-pack", cmd_verify_pack },
844 { "show-ref", cmd_show_ref, RUN_SETUP },
845 { "pack-refs", cmd_pack_refs, RUN_SETUP },
848 git_init();
850 for(i=0;i< sizeof(commands) / sizeof(struct cmd_struct);i++)
852 if(strcmp(cmd,commands[i].cmd)==0)
854 int ret;
855 if(arg != NULL)
856 argv = strtoargv(arg,&argc);
858 ret = commands[i].fn(argc, argv, NULL);
860 if(argv)
861 free(argv);
863 free_all_pack();
865 return ret;
870 return -1;
873 int git_for_each_ref_in(const char * refname, each_ref_fn fn, void * data)
875 int ret;
876 invalidate_cached_refs();
877 ret = for_each_ref_in(refname, fn, data);
878 free_all_pack();
879 return ret;
882 const char *git_resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
884 invalidate_cached_refs();
885 return resolve_ref(ref,sha1,reading, flag);
887 int git_for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data)
889 return for_each_reflog_ent(ref,fn,cb_data);
892 int git_deref_tag(const unsigned char *tagsha1, GIT_HASH refhash)
894 struct object *obj = NULL;
895 obj = parse_object(tagsha1);
896 if (!obj)
897 return -1;
899 if (obj->type == OBJ_TAG)
901 obj = deref_tag(obj, "", 0);
902 if (!obj)
903 return -1;
905 memcpy(refhash, obj->sha1, sizeof(GIT_HASH));
906 return 0;
909 return -1;
912 static int update_some(const unsigned char *sha1, const char *base, int baselen,
913 const char *pathname, unsigned mode, int stage, void *context)
915 struct cache_entry *ce;
917 ce = (struct cache_entry *)context;
919 if (S_ISDIR(mode))
920 return READ_TREE_RECURSIVE;
922 hashcpy(ce->sha1, sha1);
923 memcpy(ce->name, base, baselen);
924 memcpy(ce->name + baselen, pathname, strlen(pathname));
925 ce->ce_flags = create_ce_flags(strlen(pathname)+baselen, 0);
926 ce->ce_mode = create_ce_mode(mode);
928 return 0;
931 int git_checkout_file(const char *ref, const char *path, const char *outputpath)
933 struct cache_entry *ce;
934 int ret;
935 GIT_HASH sha1;
936 struct tree * root;
937 struct checkout state;
938 struct pathspec pathspec;
939 const char *match[2];
940 ret = get_sha1(ref, sha1);
941 if(ret)
942 return ret;
944 reprepare_packed_git();
945 root = parse_tree_indirect(sha1);
947 if(!root)
949 free_all_pack();
950 return -1;
953 ce = xcalloc(1, cache_entry_size(strlen(path)));
955 match[0] = path;
956 match[1] = NULL;
958 init_pathspec(&pathspec, match);
959 pathspec.items[0].use_wildcard = 0;
960 ret = read_tree_recursive(root, "", 0, 0, &pathspec, update_some, ce);
961 free_pathspec(&pathspec);
963 if(ret)
965 free_all_pack();
966 free(ce);
967 return ret;
969 memset(&state, 0, sizeof(state));
970 state.force = 1;
971 state.refresh_cache = 0;
973 ret = write_entry(ce, outputpath, &state, 0);
974 free_all_pack();
975 free(ce);
976 return ret;
978 struct config_buf
980 char *buf;
981 char *key;
982 char *size;
983 int seen;
986 static int get_config(const char *key_, const char *value_, void *cb)
988 struct config_buf *buf;
989 buf=(struct config_buf*)cb;
990 if(strcmp(key_, buf->key))
991 return 0;
993 if (value_)
994 strncpy(buf->buf,value_,buf->size);
995 else
997 buf->buf[0] = 't';
998 buf->buf[1] = 'r';
999 buf->buf[2] = 'u';
1000 buf->buf[3] = 'e';
1001 buf->buf[4] = 0;
1003 buf->seen = 1;
1004 return 0;
1008 static const char *get_msysgit_etc(void)
1010 char lszValue[255];
1011 HKEY hKey;
1012 DWORD dwType=REG_SZ;
1013 DWORD dwSize=255;
1014 const char * system = NULL;
1015 if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\TortoiseGit", NULL, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
1017 if (RegQueryValueEx(hKey, TEXT("MSysGit"), NULL, &dwType,(LPBYTE)&lszValue, &dwSize) == ERROR_SUCCESS)
1018 system = xstrdup(mkpath("%s/../etc/gitconfig", &lszValue));
1020 RegCloseKey(hKey);
1021 return system;
1024 int git_get_config(const char *key, char *buffer, int size, char *git_path)
1026 char *local, *global, *system;
1027 const char *home;
1028 struct config_buf buf;
1029 buf.buf=buffer;
1030 buf.size=size;
1031 buf.seen = 0;
1032 buf.key = key;
1034 local=global=system=NULL;
1036 home = get_windows_home_directory();
1037 if (home)
1038 global = xstrdup(mkpath("%s/.gitconfig", home));
1040 system = get_msysgit_etc();
1042 local = git_pathdup("config");
1044 if ( !buf.seen)
1045 git_config_from_file(get_config, local, &buf);
1046 if (!buf.seen && global)
1047 git_config_from_file(get_config, global, &buf);
1048 if (!buf.seen && system)
1049 git_config_from_file(get_config, system, &buf);
1051 if(local)
1052 free(local);
1053 if(global)
1054 free(global);
1055 if(system)
1056 free(system);
1058 return !buf.seen;
1061 // taken from msysgit: compat/mingw.c
1062 const char *get_windows_home_directory(void)
1064 static const char *home_directory = NULL;
1065 struct strbuf buf = STRBUF_INIT;
1067 if (home_directory)
1068 return home_directory;
1070 home_directory = getenv("HOME");
1071 if (home_directory && *home_directory)
1072 return home_directory;
1074 strbuf_addf(&buf, "%s/%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
1075 home_directory = strbuf_detach(&buf, NULL);
1077 return home_directory;
1080 // wchar_t wrapper for get_windows_home_directory()
1081 const wchar_t *wget_windows_home_directory(void)
1083 wchar_t * wpointer[MAX_PATH];
1084 if (xutftowcs(wpointer, get_windows_home_directory(), MAX_PATH) < 0)
1085 return NULL;
1086 return wpointer;
1089 int get_set_config(const char *key, char *value, CONFIG_TYPE type,char *git_path)
1091 switch(type)
1093 case CONFIG_LOCAL:
1094 config_exclusive_filename = git_pathdup("config");
1095 break;
1096 case CONFIG_GLOBAL:
1098 const char *home = get_windows_home_directory();
1099 if (home)
1101 config_exclusive_filename = xstrdup(mkpath("%s/.gitconfig", home));
1104 break;
1105 default:
1106 config_exclusive_filename = NULL;
1107 break;
1110 if(!config_exclusive_filename)
1111 return -1;
1113 return git_config_set(key, value);