Fixed issue #401: TGitCache.exe keeps open pack-xxx.idx on git repo
[TortoiseGit.git] / ext / gitdll / gitdll.c
blob906f56c0e6efd126d0b9f9a1e11a0e5f29cc5547
1 // gitdll.cpp : Defines the exported functions for the DLL application.
2 //
4 #include "stdafx.h"
5 #include "git-compat-util.h"
6 #include "msvc.h"
7 #include "gitdll.h"
8 #include "cache.h"
9 #include "commit.h"
10 #include "diff.h"
11 #include "revision.h"
12 #include "diffcore.h"
13 #include "dir.h"
15 const char git_version_string[] = GIT_VERSION;
18 #if 0
20 // This is an example of an exported variable
21 GITDLL_API int ngitdll=0;
23 // This is an example of an exported function.
24 GITDLL_API int fngitdll(void)
26 return 42;
29 // This is the constructor of a class that has been exported.
30 // see gitdll.h for the class definition
31 Cgitdll::Cgitdll()
33 return;
35 #endif
37 extern char g_last_error[];
38 void * g_prefix;
40 char * get_git_last_error()
42 return g_last_error;
45 extern void die_dll(const char *err, va_list params);
47 void dll_entry()
49 set_die_routine(die_dll);
52 int git_get_sha1(const char *name, GIT_HASH sha1)
54 return get_sha1(name,sha1);
57 static int convert_slash(char * path)
59 while(*path)
61 if(*path == '\\' )
62 *path = '/';
63 path++;
67 int git_init()
69 char *home;
70 char path[MAX_PATH+1];
71 char *prefix;
72 int ret;
73 size_t homesize,size,httpsize;
75 _fmode = _O_BINARY;
76 _setmode(_fileno(stdin), _O_BINARY);
77 _setmode(_fileno(stdout), _O_BINARY);
78 _setmode(_fileno(stderr), _O_BINARY);
80 // set HOME if not set already
81 getenv_s(&homesize, NULL, 0, "HOME");
82 if (!homesize)
84 _dupenv_s(&home,&size,"USERPROFILE");
85 _putenv_s("HOME",home);
86 free(home);
88 GetModuleFileName(NULL, path, MAX_PATH);
89 convert_slash(path);
91 git_extract_argv0_path(path);
92 g_prefix = prefix = setup_git_directory();
93 ret = git_config(git_default_config, NULL);
95 if (!homesize)
97 _putenv_s("HOME","");/* clear home evironment to avoid affact third part software*/
100 return ret;
103 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR *author, char *pbuff)
105 char *end;
107 author->Name=pbuff;
108 end=strchr(pbuff,'<');
109 if( end == 0)
111 return -1;
113 author->NameSize = end - pbuff - 1;
115 pbuff = end +1;
116 end = strchr(pbuff, '>');
117 if( end == 0)
118 return -1;
120 author->Email = pbuff ;
121 author->EmailSize = end - pbuff;
123 pbuff = end + 2;
125 author->Date = atol(pbuff);
126 end = strchr(pbuff, ' ');
127 if( end == 0 )
128 return -1;
130 pbuff=end;
131 author->TimeZone = atol(pbuff);
133 return 0;
136 int git_parse_commit(GIT_COMMIT *commit)
138 int ret = 0;
139 char *pbuf;
140 char *end;
141 struct commit *p;
143 p= (struct commit *)commit->m_pGitCommit;
145 memcpy(commit->m_hash,p->object.sha1,GIT_HASH_SIZE);
147 commit->m_Encode = NULL;
148 commit->m_EncodeSize = 0;
150 if(p->buffer == NULL)
151 return -1;
153 pbuf = p->buffer;
154 while(pbuf)
156 if( strncmp(pbuf,"author",6) == 0)
158 ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);
159 if(ret)
160 return ret;
162 if( strncmp(pbuf, "committer",9) == 0)
164 ret = git_parse_commit_author(&commit->m_Committer,pbuf + 10);
165 if(ret)
166 return ret;
168 pbuf = strchr(pbuf,'\n');
169 if(pbuf == NULL)
170 return -1;
172 while((*pbuf) && (*pbuf == '\n'))
173 pbuf ++;
175 if( strncmp(pbuf, "encoding",8) == 0 )
177 pbuf += 9;
178 commit->m_Encode=pbuf;
179 end = strchr(pbuf,'\n');
180 commit->m_EncodeSize=end -pbuf;
182 pbuf = end +1;
183 while((*pbuf) && (*pbuf == '\n'))
184 pbuf ++;
186 commit->m_Subject=pbuf;
187 end = strchr(pbuf,'\n');
188 if( end == 0)
189 commit->m_SubjectSize = strlen(pbuf);
190 else
192 commit->m_SubjectSize = end - pbuf;
193 pbuf = end +1;
194 commit->m_Body = pbuf;
195 commit->m_BodySize = strlen(pbuf);
196 return 0;
201 pbuf = strchr(pbuf,'\n');
202 if(pbuf)
203 pbuf ++;
208 int git_get_commit_from_hash(GIT_COMMIT *commit, GIT_HASH hash)
210 int ret = 0;
212 struct commit *p;
214 memset(commit,0,sizeof(GIT_COMMIT));
216 commit->m_pGitCommit = p = lookup_commit(hash);
218 if(commit == NULL)
219 return -1;
221 if(p == NULL)
222 return -1;
224 ret = parse_commit(p);
225 if( ret )
226 return ret;
228 return git_parse_commit(commit);
231 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)
233 struct commit *p = commit->m_pGitCommit;
235 if(list == NULL)
236 return -1;
238 *list = (GIT_COMMIT_LIST*)p->parents;
239 return 0;
241 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)
243 struct commit_list *l = *(struct commit_list **)list;
244 if(list == NULL || l==NULL)
245 return -1;
247 if(hash)
248 memcpy(hash, l->item->object.sha1, GIT_HASH_SIZE);
250 *list = (GIT_COMMIT_LIST *)l->next;
251 return 0;
256 int git_free_commit(GIT_COMMIT *commit)
258 struct commit *p = commit->m_pGitCommit;
260 if( p->parents)
261 free_commit_list(p->parents);
263 if( p->buffer )
265 free(p->buffer);
266 p->buffer=NULL;
267 p->object.parsed=0;
268 p->parents=0;
269 p->tree=0;
271 memset(commit,0,sizeof(GIT_COMMIT));
272 return 0;
275 char **strtoargv(char *arg, int *size)
277 int count=0;
278 char *p=arg;
279 char **argv;
281 int i=0;
282 while(*p)
284 if(*p == '\\')
285 *p='/';
286 p++;
288 p=arg;
290 while(*p)
292 if(*p == ' ')
293 count ++;
294 p++;
297 argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));
298 p=(char*)(argv+count+2);
300 while(*arg)
302 if(*arg == '"')
304 argv[i] = p;
305 arg++;
306 *p=*arg;
307 while(*arg && *arg!= '"')
308 *p++=*arg++;
309 *p++=0;
310 arg++;
311 i++;
312 if(*arg == 0)
313 break;
315 if(*arg != ' ')
317 argv[i]=p;
318 while(*arg && *arg !=' ')
319 *p++ = *arg++;
320 i++;
321 *p++=0;
323 arg++;
325 argv[i]=NULL;
326 *size = i;
327 return argv;
329 int git_open_log(GIT_LOG * handle, char * arg)
331 struct rev_info *p_Rev;
332 int size;
333 char ** argv=0;
334 int argc=0;
335 int i=0;
337 /* clear flags */
338 unsigned int obj_size = get_max_object_index();
339 for(i =0; i<obj_size; i++)
341 struct object *ob= get_indexed_object(i);
342 if(ob)
343 ob->flags=0;
346 if(arg != NULL)
347 argv = strtoargv(arg,&argc);
349 p_Rev = malloc(sizeof(struct rev_info));
350 memset(p_Rev,0,sizeof(struct rev_info));
352 if(p_Rev == NULL)
353 return -1;
355 init_revisions(p_Rev, g_prefix);
356 p_Rev->diff = 1;
358 cmd_log_init(argc, argv, g_prefix,p_Rev);
360 p_Rev->pPrivate = argv;
361 *handle = p_Rev;
362 return 0;
365 int git_get_log_firstcommit(GIT_LOG handle)
367 return prepare_revision_walk(handle);
370 int git_get_log_estimate_commit_count(GIT_LOG handle)
372 struct rev_info *p_Rev;
373 p_Rev=(struct rev_info *)handle;
375 return estimate_commit_count(p_Rev, p_Rev->commits);
378 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit)
380 int ret =0;
382 if(commit == NULL)
383 return -1;
385 memset(commit, 0, sizeof(GIT_COMMIT));
387 commit->m_pGitCommit = get_revision(handle);
388 if( commit->m_pGitCommit == NULL)
389 return -2;
391 ret=git_parse_commit(commit);
392 if(ret)
393 return ret;
395 return 0;
398 int git_close_log(GIT_LOG handle)
400 if(handle)
402 struct rev_info *p_Rev;
403 p_Rev=(struct rev_info *)handle;
404 if(p_Rev->pPrivate)
405 free(p_Rev->pPrivate);
406 free(handle);
409 return 0;
412 int git_open_diff(GIT_DIFF *diff, char * arg)
414 struct rev_info *p_Rev;
415 int size;
416 char ** argv=0;
417 int argc=0;
419 if(arg != NULL)
420 argv = strtoargv(arg,&argc);
422 p_Rev = malloc(sizeof(struct rev_info));
423 memset(p_Rev,0,sizeof(struct rev_info));
425 p_Rev->pPrivate = argv;
426 *diff = (GIT_DIFF)p_Rev;
428 init_revisions(p_Rev, g_prefix);
429 git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
430 p_Rev->abbrev = 0;
431 p_Rev->diff = 1;
432 argc = setup_revisions(argc, argv, p_Rev, NULL);
434 return 0;
436 int git_close_diff(GIT_DIFF handle)
438 git_diff_flush(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 return 0;
449 int git_diff_flush(GIT_DIFF diff)
451 struct diff_queue_struct *q = &diff_queued_diff;
452 struct rev_info *p_Rev;
453 int i;
454 p_Rev = (struct rev_info *)diff;
456 if(q->nr == 0)
457 return 0;
459 for (i = 0; i < q->nr; i++)
460 diff_free_filepair(q->queue[i]);
462 if(q->queue)
464 free(q->queue);
465 q->queue = NULL;
466 q->nr = q->alloc = 0;
469 if (p_Rev->diffopt.close_file)
470 fclose(p_Rev->diffopt.close_file);
472 free_diffstat_info(&p_Rev->diffstat);
475 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count)
477 int ret;
478 struct rev_info *p_Rev;
479 int i;
480 struct diff_queue_struct *q = &diff_queued_diff;
482 p_Rev = (struct rev_info *)diff;
484 ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);
486 if(ret)
487 return ret;
489 diffcore_std(&p_Rev->diffopt);
491 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
492 for (i = 0; i < q->nr; i++) {
493 struct diff_filepair *p = q->queue[i];
494 //if (check_pair_status(p))
495 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
498 if(file)
499 *file = q;
500 if(count)
501 *count = q->nr;
503 return 0;
506 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count)
508 struct rev_info *p_Rev;
509 int ret;
510 int i;
511 struct diff_queue_struct *q = &diff_queued_diff;
513 p_Rev = (struct rev_info *)diff;
515 ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);
516 if( ret )
517 return ret;
519 diffcore_std(&p_Rev->diffopt);
521 memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));
522 for (i = 0; i < q->nr; i++) {
523 struct diff_filepair *p = q->queue[i];
524 //if (check_pair_status(p))
525 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);
528 if(file)
529 *file = q;
530 if(count)
531 *count = q->nr;
532 return 0;
535 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)
537 struct diff_queue_struct *q = &diff_queued_diff;
538 struct rev_info *p_Rev;
539 p_Rev = (struct rev_info *)diff;
541 q = (struct diff_queue_struct *)file;
542 if(file == 0)
543 return -1;
544 if(i>=q->nr)
545 return -1;
547 if(newname)
548 *newname = q->queue[i]->two->path;
550 if(oldname)
551 *oldname = q->queue[i]->one->path;
553 if(status)
554 *status = q->queue[i]->status;
556 if(p_Rev->diffstat.files)
558 int j;
559 for(j=0;j<p_Rev->diffstat.nr;j++)
561 if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)
562 break;
564 if( j== p_Rev->diffstat.nr)
566 *IsBin=1;
567 *inc=0;
568 *dec=0;
569 return 0;
571 if(IsBin)
572 *IsBin = p_Rev->diffstat.files[j]->is_binary;
573 if(inc)
574 *inc = p_Rev->diffstat.files[j]->added;
575 if(dec)
576 *dec = p_Rev->diffstat.files[j]->deleted;
577 }else
579 *IsBin=1;
580 *inc=0;
581 *dec=0;
584 return 0;
587 int git_read_tree(GIT_HASH hash,read_tree_fn_t fn, void *context)
589 struct tree * root;
590 int ret;
591 reprepare_packed_git();
592 root = parse_tree_indirect(hash);
594 if (!root)
596 free_all_pack();
597 return -1;
599 ret = read_tree_recursive(root,NULL,NULL,0,NULL,fn,context);
600 free_all_pack();
601 return ret;
604 int git_add_exclude(const char *string, const char *base,
605 int baselen, struct exclude_list *which)
607 add_exclude(string, base, baselen, which);
608 return 0;
611 int git_create_exclude_list(EXCLUDE_LIST *which)
613 *which = malloc(sizeof(struct exclude_list));
614 memset(*which,0,sizeof(struct exclude_list));
615 return 0;
618 int git_free_exclude_list(EXCLUDE_LIST which)
620 int i=0;
621 struct exclude_list *p = (struct exclude_list *) which;
623 for(i=0; i<p->nr;i++)
625 free(p->excludes[i]);
627 free(p->excludes);
628 free(p);
631 int git_check_excluded_1(const char *pathname,
632 int pathlen, const char *basename, int *dtype,
633 EXCLUDE_LIST el)
635 return excluded_1(pathname, pathlen, basename,dtype,el);