OSDN Git Service

Show Progress percentage at log dialog
[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         if(p->buffer == NULL)\r
138                 return -1;\r
139 \r
140         pbuf = p->buffer;\r
141         while(pbuf)\r
142         {\r
143                 if( strncmp(pbuf,"author",6) == 0)\r
144                 {\r
145                         ret = git_parse_commit_author(&commit->m_Author,pbuf + 7);\r
146                         if(ret)\r
147                                 return ret;\r
148                 }\r
149                 if( strncmp(pbuf, "committer",9) == 0)\r
150                 {\r
151                         ret =  git_parse_commit_author(&commit->m_Committer,pbuf + 10);\r
152                         if(ret)\r
153                                 return ret;\r
154 \r
155                         pbuf = strchr(pbuf,'\n');\r
156                         if(pbuf == NULL)\r
157                                 return -1;\r
158 \r
159                         while((*pbuf) && (*pbuf == '\n'))\r
160                                 pbuf ++;\r
161 \r
162                         commit->m_Subject=pbuf;\r
163                         end = strchr(pbuf,'\n');\r
164                         if( end == 0)\r
165                                 commit->m_SubjectSize = strlen(pbuf);\r
166                         else\r
167                         {\r
168                                 commit->m_SubjectSize = end - pbuf;\r
169                                 pbuf = end +1;\r
170                                 commit->m_Body = pbuf;\r
171                                 commit->m_BodySize = strlen(pbuf);\r
172                                 return 0;\r
173                         }\r
174 \r
175                 }\r
176 \r
177                 pbuf = strchr(pbuf,'\n');\r
178                 if(pbuf)\r
179                         pbuf ++;\r
180         }\r
181 \r
182 }\r
183 \r
184 int git_get_commit_from_hash(GIT_COMMIT *commit, GIT_HASH hash)\r
185 {\r
186         int ret = 0;\r
187         \r
188         struct commit *p;\r
189         commit->m_pGitCommit = p = lookup_commit(hash);\r
190 \r
191         if(commit == NULL)\r
192                 return -1;\r
193         \r
194         if(p == NULL)\r
195                 return -1;\r
196         \r
197         ret = parse_commit(p);\r
198         if( ret )\r
199                 return ret;\r
200 \r
201         return git_parse_commit(commit);\r
202 }\r
203 \r
204 int git_get_commit_first_parent(GIT_COMMIT *commit,GIT_COMMIT_LIST *list)\r
205 {\r
206         struct commit *p = commit->m_pGitCommit;\r
207 \r
208         if(list == NULL)\r
209                 return -1;\r
210         \r
211         *list = (GIT_COMMIT_LIST*)p->parents;\r
212         return 0;\r
213 }\r
214 int git_get_commit_next_parent(GIT_COMMIT_LIST *list, GIT_HASH hash)\r
215 {\r
216         struct commit_list *l = *(struct commit_list **)list;\r
217         if(list == NULL || l==NULL)\r
218                 return -1;\r
219 \r
220         if(hash)\r
221                 memcpy(hash, l->item->object.sha1, GIT_HASH_SIZE);\r
222 \r
223         *list = (GIT_COMMIT_LIST *)l->next;\r
224         return 0;\r
225 \r
226 }\r
227 \r
228 \r
229 int git_free_commit(GIT_COMMIT *commit)\r
230 {\r
231         struct commit *p = commit->m_pGitCommit;\r
232 \r
233         if( p->parents)\r
234                 free_commit_list(p->parents);   \r
235 \r
236         if( p->buffer )\r
237         {\r
238                 free(p->buffer);\r
239                 p->buffer=NULL;\r
240                 p->object.parsed=0;\r
241                 p->parents=0;\r
242                 p->tree=0;\r
243         }\r
244         memset(commit,0,sizeof(GIT_COMMIT));\r
245         return 0;\r
246 }\r
247 \r
248 char **strtoargv(char *arg, int *size)\r
249 {\r
250         int count=0;\r
251         char *p=arg;\r
252         char **argv;\r
253         int i=0;\r
254         while(*p)\r
255         {\r
256                 if(*p == ' ')\r
257                         count ++;\r
258                 p++;\r
259         }\r
260         \r
261         argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));\r
262         p=(char*)(argv+count+2);\r
263 \r
264         while(*arg)\r
265         {\r
266                 if(*arg == '"')\r
267                 {\r
268                         argv[i] = p;\r
269                         arg++;\r
270                         *p=*arg;\r
271                         while(*arg && *arg!= '"')\r
272                                 *p++=*arg++;\r
273                         *p++=0;\r
274                         arg++;\r
275                         i++;\r
276                         if(*arg == 0)\r
277                                 break;\r
278                 }\r
279                 if(*arg != ' ')\r
280                 {\r
281                         argv[i]=p;\r
282                         while(*arg && *arg !=' ')\r
283                                 *p++ = *arg++;\r
284                         i++;\r
285                         *p++=0;\r
286                 }\r
287                 arg++;\r
288         }\r
289         argv[i]=NULL;\r
290         *size = i;\r
291         return argv;\r
292 }\r
293 int git_open_log(GIT_LOG * handle, char * arg)\r
294 {\r
295         struct rev_info *p_Rev;\r
296         int size;\r
297         char ** argv=0;\r
298         int argc=0;\r
299         int i=0;\r
300 \r
301         /* clear flags */\r
302         unsigned int obj_size = get_max_object_index();\r
303         for(i =0; i<obj_size; i++)\r
304         {\r
305                 struct object *ob= get_indexed_object(i);\r
306                 if(ob)\r
307                         ob->flags=0;\r
308         }\r
309 \r
310         if(arg != NULL)\r
311                 argv = strtoargv(arg,&argc);\r
312 \r
313         p_Rev = malloc(sizeof(struct rev_info));\r
314         memset(p_Rev,0,sizeof(struct rev_info));\r
315 \r
316         if(p_Rev == NULL)\r
317                 return -1;\r
318 \r
319         init_revisions(p_Rev, g_prefix);\r
320         p_Rev->diff = 1;\r
321         p_Rev->simplify_history = 0;\r
322         \r
323         cmd_log_init(argc, argv, g_prefix,p_Rev);\r
324 \r
325         p_Rev->pPrivate = argv;\r
326         *handle = p_Rev;\r
327         return 0;\r
328 \r
329 }\r
330 int git_get_log_firstcommit(GIT_LOG handle)\r
331 {\r
332         return prepare_revision_walk(handle);\r
333 }\r
334 \r
335 int git_get_log_estimate_commit_count(GIT_LOG handle)\r
336 {\r
337         struct rev_info *p_Rev;\r
338         p_Rev=(struct rev_info *)handle;\r
339 \r
340         return estimate_commit_count(p_Rev, p_Rev->commits);\r
341 }\r
342 \r
343 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit)\r
344 {\r
345         int ret =0;\r
346 \r
347         commit->m_pGitCommit = get_revision(handle);\r
348         if( commit->m_pGitCommit == NULL)\r
349                 return -2;\r
350         \r
351         ret=git_parse_commit(commit);\r
352         if(ret)\r
353                 return ret;\r
354 \r
355         return 0;\r
356 }\r
357 \r
358 int git_close_log(GIT_LOG handle)\r
359 {\r
360         if(handle)\r
361         {\r
362                 struct rev_info *p_Rev;\r
363                 p_Rev=(struct rev_info *)handle;\r
364                 if(p_Rev->pPrivate)\r
365                         free(p_Rev->pPrivate);\r
366                 free(handle);\r
367         }\r
368         \r
369         return 0;\r
370 }\r
371 \r
372 int git_open_diff(GIT_DIFF *diff, char * arg)\r
373 {\r
374         struct rev_info *p_Rev;\r
375         int size;\r
376         char ** argv=0;\r
377         int argc=0;\r
378                 \r
379         if(arg != NULL)\r
380                 argv = strtoargv(arg,&argc);\r
381 \r
382         p_Rev = malloc(sizeof(struct rev_info));\r
383         memset(p_Rev,0,sizeof(struct rev_info));\r
384 \r
385         p_Rev->pPrivate = argv;\r
386         *diff = (GIT_DIFF)p_Rev;\r
387 \r
388         init_revisions(p_Rev, g_prefix);\r
389         git_config(git_diff_basic_config, NULL); /* no "diff" UI options */\r
390         p_Rev->abbrev = 0;\r
391         p_Rev->diff = 1;\r
392         argc = setup_revisions(argc, argv, p_Rev, NULL);\r
393 \r
394         return 0;\r
395 }\r
396 int git_close_diff(GIT_DIFF handle)\r
397 {\r
398         git_diff_flush(handle);\r
399         if(handle)\r
400         {\r
401                 struct rev_info *p_Rev;\r
402                 p_Rev=(struct rev_info *)handle;\r
403                 if(p_Rev->pPrivate)\r
404                         free(p_Rev->pPrivate);\r
405                 free(handle);\r
406         }\r
407         return 0;\r
408 }\r
409 int git_diff_flush(GIT_DIFF diff)\r
410 {\r
411         struct diff_queue_struct *q = &diff_queued_diff;\r
412         struct rev_info *p_Rev;\r
413         int i;\r
414         p_Rev = (struct rev_info *)diff;\r
415         \r
416         if(q->nr == 0)\r
417                 return 0;\r
418 \r
419         for (i = 0; i < q->nr; i++)\r
420                 diff_free_filepair(q->queue[i]);\r
421 \r
422         if(q->queue)\r
423         {\r
424                 free(q->queue);\r
425                 q->queue = NULL;\r
426                 q->nr = q->alloc = 0;\r
427         }\r
428 \r
429         if (p_Rev->diffopt.close_file)\r
430                 fclose(p_Rev->diffopt.close_file);\r
431 \r
432         free_diffstat_info(&p_Rev->diffstat);\r
433 }\r
434 \r
435 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count)\r
436 {\r
437         int ret;\r
438         struct rev_info *p_Rev;\r
439         int i;\r
440         struct diff_queue_struct *q = &diff_queued_diff;\r
441 \r
442         p_Rev = (struct rev_info *)diff;\r
443 \r
444         ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);\r
445 \r
446         if(ret)\r
447                 return ret;\r
448 \r
449         diffcore_std(&p_Rev->diffopt);\r
450 \r
451         memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));\r
452         for (i = 0; i < q->nr; i++) {\r
453                 struct diff_filepair *p = q->queue[i];\r
454                 //if (check_pair_status(p))\r
455                 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);\r
456         }\r
457 \r
458         if(file)\r
459                 *file = q;\r
460         if(count)\r
461                 *count = q->nr;\r
462 \r
463         return 0;\r
464 }\r
465 \r
466 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count)\r
467 {\r
468         struct rev_info *p_Rev;\r
469         int ret;\r
470         int i;\r
471         struct diff_queue_struct *q = &diff_queued_diff;\r
472         \r
473         p_Rev = (struct rev_info *)diff;\r
474 \r
475         ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);\r
476         if( ret )\r
477                 return ret;\r
478         \r
479         diffcore_std(&p_Rev->diffopt);\r
480 \r
481         memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));\r
482         for (i = 0; i < q->nr; i++) {\r
483                 struct diff_filepair *p = q->queue[i];\r
484                 //if (check_pair_status(p))\r
485                 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);\r
486         }\r
487 \r
488         if(file)\r
489                 *file = q;\r
490         if(count)\r
491                 *count = q->nr;\r
492         return 0;\r
493 }\r
494 \r
495 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
496 {\r
497         struct diff_queue_struct *q = &diff_queued_diff;\r
498         struct rev_info *p_Rev;\r
499         p_Rev = (struct rev_info *)diff;\r
500         \r
501         q = (struct diff_queue_struct *)file;\r
502         if(file == 0)\r
503                 return -1;\r
504         if(i>=q->nr)\r
505                 return -1;\r
506 \r
507         if(newname)\r
508                 *newname = q->queue[i]->one->path;\r
509 \r
510         if(oldname)\r
511                 *oldname = q->queue[i]->two->path;\r
512 \r
513         if(status)\r
514                 *status = q->queue[i]->status;\r
515 \r
516         if(p_Rev->diffstat.files)\r
517         {\r
518                 int j;\r
519                 for(j=0;j<p_Rev->diffstat.nr;j++)\r
520                 {\r
521                         if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)\r
522                                 break;\r
523                 }\r
524                 if( j== p_Rev->diffstat.nr)\r
525                 {\r
526                         *IsBin=1;\r
527                         *inc=0;\r
528                         *dec=0;\r
529                         return 0;\r
530                 }\r
531                 if(IsBin)\r
532                         *IsBin = p_Rev->diffstat.files[j]->is_binary;\r
533                 if(inc)\r
534                         *inc = p_Rev->diffstat.files[j]->added;\r
535                 if(dec)\r
536                         *dec = p_Rev->diffstat.files[j]->deleted;\r
537         }else\r
538         {\r
539                 *IsBin=1;\r
540                 *inc=0;\r
541                 *dec=0;\r
542         }\r
543 \r
544         return 0;\r
545 }