OSDN Git Service

Fix file history wrong
[tortoisegit/TortoiseGitJp.git] / ext / gitdll / gitdll.c
1 // gitdll.cpp : Defines the exported functions for the DLL application.\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "git-compat-util.h"\r
6 #include "msvc.h"\r
7 #include "gitdll.h"\r
8 #include "cache.h"\r
9 #include "commit.h"\r
10 #include "diff.h"\r
11 #include "revision.h"\r
12 #include "diffcore.h"\r
13 const char git_version_string[] = GIT_VERSION;\r
14 \r
15 \r
16 #if 0\r
17 \r
18 // This is an example of an exported variable\r
19 GITDLL_API int ngitdll=0;\r
20 \r
21 // This is an example of an exported function.\r
22 GITDLL_API int fngitdll(void)\r
23 {\r
24         return 42;\r
25 }\r
26 \r
27 // This is the constructor of a class that has been exported.\r
28 // see gitdll.h for the class definition\r
29 Cgitdll::Cgitdll()\r
30 {\r
31         return;\r
32 }\r
33 #endif\r
34 \r
35 #define MAX_ERROR_STR_SIZE 512\r
36 char g_last_error[MAX_ERROR_STR_SIZE]={0};\r
37 void * g_prefix;\r
38 \r
39 char * get_git_last_error()\r
40 {\r
41         return g_last_error;\r
42 }\r
43 \r
44 static void die_dll(const char *err, va_list params)\r
45 {\r
46         memset(g_last_error,0,MAX_ERROR_STR_SIZE);\r
47         vsnprintf(g_last_error, MAX_ERROR_STR_SIZE-1, err, params);     \r
48 }\r
49 \r
50 void dll_entry()\r
51 {\r
52         set_die_routine(die_dll);\r
53 }\r
54 \r
55 int git_get_sha1(const char *name, GIT_HASH sha1)\r
56 {\r
57         return get_sha1(name,sha1);\r
58 }\r
59 \r
60 static int convert_slash(char * path)\r
61 {\r
62         while(*path)\r
63         {\r
64                 if(*path == '\\' )\r
65                         *path = '/';\r
66                 path++;\r
67         }\r
68 }\r
69 \r
70 int git_init()\r
71 {\r
72         char *home;\r
73         char path[MAX_PATH+1];\r
74         char *prefix;\r
75         size_t homesize,size,httpsize;\r
76 \r
77         // set HOME if not set already\r
78         getenv_s(&homesize, NULL, 0, "HOME");\r
79         if (!homesize)\r
80         {\r
81                 _dupenv_s(&home,&size,"USERPROFILE"); \r
82                 _putenv_s("HOME",home);\r
83                 free(home);\r
84         }\r
85         GetModuleFileName(NULL, path, MAX_PATH);\r
86         convert_slash(path);\r
87 \r
88         git_extract_argv0_path(path);\r
89         g_prefix = prefix = setup_git_directory();\r
90         return git_config(git_default_config, NULL);\r
91 }\r
92 \r
93 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR *author, char *pbuff)\r
94 {\r
95         char *end;\r
96 \r
97         author->Name=pbuff;\r
98         end=strchr(pbuff,'<');\r
99         if( end == 0)\r
100         {\r
101                 return -1;\r
102         }\r
103         author->NameSize = end - pbuff - 1;\r
104 \r
105         pbuff = end +1;\r
106         end = strchr(pbuff, '>');\r
107         if( end == 0)\r
108                 return -1;\r
109 \r
110         author->Email = pbuff ;\r
111         author->EmailSize = end - pbuff;\r
112 \r
113         pbuff = end + 2;\r
114 \r
115         author->Date = atol(pbuff);\r
116         end =  strchr(pbuff, ' ');\r
117         if( end == 0 )\r
118                 return -1;\r
119 \r
120         pbuff=end;\r
121         author->TimeZone = atol(pbuff);\r
122 \r
123         return 0;\r
124 }\r
125 \r
126 int git_parse_commit(GIT_COMMIT *commit)\r
127 {\r
128         int ret = 0;\r
129         char *pbuf;\r
130         char *end;\r
131         struct commit *p;\r
132 \r
133         p= (struct commit *)commit->m_pGitCommit;\r
134 \r
135         memcpy(commit->m_hash,p->object.sha1,GIT_HASH_SIZE);\r
136 \r
137         commit->m_Encode = NULL;\r
138         commit->m_EncodeSize = 0;\r
139 \r
140         if(p->buffer == NULL)\r
141                 return -1;\r
142 \r
143         pbuf = p->buffer;\r
144         while(pbuf)\r
145         {\r
146                 if( strncmp(pbuf,"author",6) == 0)\r
147                 {\r
148                         ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);\r
149                         if(ret)\r
150                                 return ret;\r
151                 }\r
152                 if( strncmp(pbuf, "committer",9) == 0)\r
153                 {\r
154                         ret =  git_parse_commit_author(&commit->m_Committer,pbuf + 10);\r
155                         if(ret)\r
156                                 return ret;\r
157 \r
158                         pbuf = strchr(pbuf,'\n');\r
159                         if(pbuf == NULL)\r
160                                 return -1;\r
161 \r
162                         while((*pbuf) && (*pbuf == '\n'))\r
163                                 pbuf ++;\r
164 \r
165                         if( strncmp(pbuf, "encoding",8) == 0 )\r
166                         {\r
167                                 pbuf += 9;\r
168                                 commit->m_Encode=pbuf;\r
169                                 end = strchr(pbuf,'\n');\r
170                                 commit->m_EncodeSize=end -pbuf;\r
171 \r
172                                 pbuf = end +1;\r
173                                 while((*pbuf) && (*pbuf == '\n'))\r
174                                         pbuf ++;\r
175                         }\r
176                         commit->m_Subject=pbuf;\r
177                         end = strchr(pbuf,'\n');\r
178                         if( end == 0)\r
179                                 commit->m_SubjectSize = strlen(pbuf);\r
180                         else\r
181                         {\r
182                                 commit->m_SubjectSize = end - pbuf;\r
183                                 pbuf = end +1;\r
184                                 commit->m_Body = pbuf;\r
185                                 commit->m_BodySize = strlen(pbuf);\r
186                                 return 0;\r
187                         }\r
188 \r
189                 }\r
190 \r
191                 pbuf = strchr(pbuf,'\n');\r
192                 if(pbuf)\r
193                         pbuf ++;\r
194         }\r
195 \r
196 }\r
197 \r
198 int git_get_commit_from_hash(GIT_COMMIT *commit, GIT_HASH hash)\r
199 {\r
200         int ret = 0;\r
201         \r
202         struct commit *p;\r
203         \r
204         memset(commit,0,sizeof(GIT_COMMIT));\r
205 \r
206         commit->m_pGitCommit = p = lookup_commit(hash);\r
207 \r
208         if(commit == NULL)\r
209                 return -1;\r
210         \r
211         if(p == NULL)\r
212                 return -1;\r
213         \r
214         ret = parse_commit(p);\r
215         if( ret )\r
216                 return ret;\r
217 \r
218         return git_parse_commit(commit);\r
219 }\r
220 \r
221 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)\r
222 {\r
223         struct commit *p = commit->m_pGitCommit;\r
224 \r
225         if(list == NULL)\r
226                 return -1;\r
227         \r
228         *list = (GIT_COMMIT_LIST*)p->parents;\r
229         return 0;\r
230 }\r
231 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)\r
232 {\r
233         struct commit_list *l = *(struct commit_list **)list;\r
234         if(list == NULL || l==NULL)\r
235                 return -1;\r
236 \r
237         if(hash)\r
238                 memcpy(hash, l->item->object.sha1, GIT_HASH_SIZE);\r
239 \r
240         *list = (GIT_COMMIT_LIST *)l->next;\r
241         return 0;\r
242 \r
243 }\r
244 \r
245 \r
246 int git_free_commit(GIT_COMMIT *commit)\r
247 {\r
248         struct commit *p = commit->m_pGitCommit;\r
249 \r
250         if( p->parents)\r
251                 free_commit_list(p->parents);   \r
252 \r
253         if( p->buffer )\r
254         {\r
255                 free(p->buffer);\r
256                 p->buffer=NULL;\r
257                 p->object.parsed=0;\r
258                 p->parents=0;\r
259                 p->tree=0;\r
260         }\r
261         memset(commit,0,sizeof(GIT_COMMIT));\r
262         return 0;\r
263 }\r
264 \r
265 char **strtoargv(char *arg, int *size)\r
266 {\r
267         int count=0;\r
268         char *p=arg;\r
269         char **argv;\r
270         \r
271         int i=0;\r
272         while(*p)\r
273         {\r
274                 if(*p == '\\')\r
275                         *p='/';\r
276                 p++;\r
277         }\r
278         p=arg;\r
279 \r
280         while(*p)\r
281         {\r
282                 if(*p == ' ')\r
283                         count ++;\r
284                 p++;\r
285         }\r
286         \r
287         argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));\r
288         p=(char*)(argv+count+2);\r
289 \r
290         while(*arg)\r
291         {\r
292                 if(*arg == '"')\r
293                 {\r
294                         argv[i] = p;\r
295                         arg++;\r
296                         *p=*arg;\r
297                         while(*arg && *arg!= '"')\r
298                                 *p++=*arg++;\r
299                         *p++=0;\r
300                         arg++;\r
301                         i++;\r
302                         if(*arg == 0)\r
303                                 break;\r
304                 }\r
305                 if(*arg != ' ')\r
306                 {\r
307                         argv[i]=p;\r
308                         while(*arg && *arg !=' ')\r
309                                 *p++ = *arg++;\r
310                         i++;\r
311                         *p++=0;\r
312                 }\r
313                 arg++;\r
314         }\r
315         argv[i]=NULL;\r
316         *size = i;\r
317         return argv;\r
318 }\r
319 int git_open_log(GIT_LOG * handle, char * arg)\r
320 {\r
321         struct rev_info *p_Rev;\r
322         int size;\r
323         char ** argv=0;\r
324         int argc=0;\r
325         int i=0;\r
326 \r
327         /* clear flags */\r
328         unsigned int obj_size = get_max_object_index();\r
329         for(i =0; i<obj_size; i++)\r
330         {\r
331                 struct object *ob= get_indexed_object(i);\r
332                 if(ob)\r
333                         ob->flags=0;\r
334         }\r
335 \r
336         if(arg != NULL)\r
337                 argv = strtoargv(arg,&argc);\r
338 \r
339         p_Rev = malloc(sizeof(struct rev_info));\r
340         memset(p_Rev,0,sizeof(struct rev_info));\r
341 \r
342         if(p_Rev == NULL)\r
343                 return -1;\r
344 \r
345         init_revisions(p_Rev, g_prefix);\r
346         p_Rev->diff = 1;\r
347                 \r
348         cmd_log_init(argc, argv, g_prefix,p_Rev);\r
349 \r
350         p_Rev->pPrivate = argv;\r
351         *handle = p_Rev;\r
352         return 0;\r
353 \r
354 }\r
355 int git_get_log_firstcommit(GIT_LOG handle)\r
356 {\r
357         return prepare_revision_walk(handle);\r
358 }\r
359 \r
360 int git_get_log_estimate_commit_count(GIT_LOG handle)\r
361 {\r
362         struct rev_info *p_Rev;\r
363         p_Rev=(struct rev_info *)handle;\r
364 \r
365         return estimate_commit_count(p_Rev, p_Rev->commits);\r
366 }\r
367 \r
368 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit)\r
369 {\r
370         int ret =0;\r
371 \r
372         commit->m_pGitCommit = get_revision(handle);\r
373         if( commit->m_pGitCommit == NULL)\r
374                 return -2;\r
375         \r
376         ret=git_parse_commit(commit);\r
377         if(ret)\r
378                 return ret;\r
379 \r
380         return 0;\r
381 }\r
382 \r
383 int git_close_log(GIT_LOG handle)\r
384 {\r
385         if(handle)\r
386         {\r
387                 struct rev_info *p_Rev;\r
388                 p_Rev=(struct rev_info *)handle;\r
389                 if(p_Rev->pPrivate)\r
390                         free(p_Rev->pPrivate);\r
391                 free(handle);\r
392         }\r
393         \r
394         return 0;\r
395 }\r
396 \r
397 int git_open_diff(GIT_DIFF *diff, char * arg)\r
398 {\r
399         struct rev_info *p_Rev;\r
400         int size;\r
401         char ** argv=0;\r
402         int argc=0;\r
403                 \r
404         if(arg != NULL)\r
405                 argv = strtoargv(arg,&argc);\r
406 \r
407         p_Rev = malloc(sizeof(struct rev_info));\r
408         memset(p_Rev,0,sizeof(struct rev_info));\r
409 \r
410         p_Rev->pPrivate = argv;\r
411         *diff = (GIT_DIFF)p_Rev;\r
412 \r
413         init_revisions(p_Rev, g_prefix);\r
414         git_config(git_diff_basic_config, NULL); /* no "diff" UI options */\r
415         p_Rev->abbrev = 0;\r
416         p_Rev->diff = 1;\r
417         argc = setup_revisions(argc, argv, p_Rev, NULL);\r
418 \r
419         return 0;\r
420 }\r
421 int git_close_diff(GIT_DIFF handle)\r
422 {\r
423         git_diff_flush(handle);\r
424         if(handle)\r
425         {\r
426                 struct rev_info *p_Rev;\r
427                 p_Rev=(struct rev_info *)handle;\r
428                 if(p_Rev->pPrivate)\r
429                         free(p_Rev->pPrivate);\r
430                 free(handle);\r
431         }\r
432         return 0;\r
433 }\r
434 int git_diff_flush(GIT_DIFF diff)\r
435 {\r
436         struct diff_queue_struct *q = &diff_queued_diff;\r
437         struct rev_info *p_Rev;\r
438         int i;\r
439         p_Rev = (struct rev_info *)diff;\r
440         \r
441         if(q->nr == 0)\r
442                 return 0;\r
443 \r
444         for (i = 0; i < q->nr; i++)\r
445                 diff_free_filepair(q->queue[i]);\r
446 \r
447         if(q->queue)\r
448         {\r
449                 free(q->queue);\r
450                 q->queue = NULL;\r
451                 q->nr = q->alloc = 0;\r
452         }\r
453 \r
454         if (p_Rev->diffopt.close_file)\r
455                 fclose(p_Rev->diffopt.close_file);\r
456 \r
457         free_diffstat_info(&p_Rev->diffstat);\r
458 }\r
459 \r
460 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count)\r
461 {\r
462         int ret;\r
463         struct rev_info *p_Rev;\r
464         int i;\r
465         struct diff_queue_struct *q = &diff_queued_diff;\r
466 \r
467         p_Rev = (struct rev_info *)diff;\r
468 \r
469         ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);\r
470 \r
471         if(ret)\r
472                 return ret;\r
473 \r
474         diffcore_std(&p_Rev->diffopt);\r
475 \r
476         memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));\r
477         for (i = 0; i < q->nr; i++) {\r
478                 struct diff_filepair *p = q->queue[i];\r
479                 //if (check_pair_status(p))\r
480                 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);\r
481         }\r
482 \r
483         if(file)\r
484                 *file = q;\r
485         if(count)\r
486                 *count = q->nr;\r
487 \r
488         return 0;\r
489 }\r
490 \r
491 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count)\r
492 {\r
493         struct rev_info *p_Rev;\r
494         int ret;\r
495         int i;\r
496         struct diff_queue_struct *q = &diff_queued_diff;\r
497         \r
498         p_Rev = (struct rev_info *)diff;\r
499 \r
500         ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);\r
501         if( ret )\r
502                 return ret;\r
503         \r
504         diffcore_std(&p_Rev->diffopt);\r
505 \r
506         memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));\r
507         for (i = 0; i < q->nr; i++) {\r
508                 struct diff_filepair *p = q->queue[i];\r
509                 //if (check_pair_status(p))\r
510                 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);\r
511         }\r
512 \r
513         if(file)\r
514                 *file = q;\r
515         if(count)\r
516                 *count = q->nr;\r
517         return 0;\r
518 }\r
519 \r
520 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)\r
521 {\r
522         struct diff_queue_struct *q = &diff_queued_diff;\r
523         struct rev_info *p_Rev;\r
524         p_Rev = (struct rev_info *)diff;\r
525         \r
526         q = (struct diff_queue_struct *)file;\r
527         if(file == 0)\r
528                 return -1;\r
529         if(i>=q->nr)\r
530                 return -1;\r
531 \r
532         if(newname)\r
533                 *newname = q->queue[i]->two->path;\r
534 \r
535         if(oldname)\r
536                 *oldname = q->queue[i]->one->path;\r
537 \r
538         if(status)\r
539                 *status = q->queue[i]->status;\r
540 \r
541         if(p_Rev->diffstat.files)\r
542         {\r
543                 int j;\r
544                 for(j=0;j<p_Rev->diffstat.nr;j++)\r
545                 {\r
546                         if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)\r
547                                 break;\r
548                 }\r
549                 if( j== p_Rev->diffstat.nr)\r
550                 {\r
551                         *IsBin=1;\r
552                         *inc=0;\r
553                         *dec=0;\r
554                         return 0;\r
555                 }\r
556                 if(IsBin)\r
557                         *IsBin = p_Rev->diffstat.files[j]->is_binary;\r
558                 if(inc)\r
559                         *inc = p_Rev->diffstat.files[j]->added;\r
560                 if(dec)\r
561                         *dec = p_Rev->diffstat.files[j]->deleted;\r
562         }else\r
563         {\r
564                 *IsBin=1;\r
565                 *inc=0;\r
566                 *dec=0;\r
567         }\r
568 \r
569         return 0;\r
570 }