OSDN Git Service

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