OSDN Git Service

7ff8967f0d09e761327a86efee1c584f326f0704
[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         int i=0;\r
271         while(*p)\r
272         {\r
273                 if(*p == ' ')\r
274                         count ++;\r
275                 p++;\r
276         }\r
277         \r
278         argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));\r
279         p=(char*)(argv+count+2);\r
280 \r
281         while(*arg)\r
282         {\r
283                 if(*arg == '"')\r
284                 {\r
285                         argv[i] = p;\r
286                         arg++;\r
287                         *p=*arg;\r
288                         while(*arg && *arg!= '"')\r
289                                 *p++=*arg++;\r
290                         *p++=0;\r
291                         arg++;\r
292                         i++;\r
293                         if(*arg == 0)\r
294                                 break;\r
295                 }\r
296                 if(*arg != ' ')\r
297                 {\r
298                         argv[i]=p;\r
299                         while(*arg && *arg !=' ')\r
300                                 *p++ = *arg++;\r
301                         i++;\r
302                         *p++=0;\r
303                 }\r
304                 arg++;\r
305         }\r
306         argv[i]=NULL;\r
307         *size = i;\r
308         return argv;\r
309 }\r
310 int git_open_log(GIT_LOG * handle, char * arg)\r
311 {\r
312         struct rev_info *p_Rev;\r
313         int size;\r
314         char ** argv=0;\r
315         int argc=0;\r
316         int i=0;\r
317 \r
318         /* clear flags */\r
319         unsigned int obj_size = get_max_object_index();\r
320         for(i =0; i<obj_size; i++)\r
321         {\r
322                 struct object *ob= get_indexed_object(i);\r
323                 if(ob)\r
324                         ob->flags=0;\r
325         }\r
326 \r
327         if(arg != NULL)\r
328                 argv = strtoargv(arg,&argc);\r
329 \r
330         p_Rev = malloc(sizeof(struct rev_info));\r
331         memset(p_Rev,0,sizeof(struct rev_info));\r
332 \r
333         if(p_Rev == NULL)\r
334                 return -1;\r
335 \r
336         init_revisions(p_Rev, g_prefix);\r
337         p_Rev->diff = 1;\r
338         p_Rev->simplify_history = 0;\r
339         \r
340         cmd_log_init(argc, argv, g_prefix,p_Rev);\r
341 \r
342         p_Rev->pPrivate = argv;\r
343         *handle = p_Rev;\r
344         return 0;\r
345 \r
346 }\r
347 int git_get_log_firstcommit(GIT_LOG handle)\r
348 {\r
349         return prepare_revision_walk(handle);\r
350 }\r
351 \r
352 int git_get_log_estimate_commit_count(GIT_LOG handle)\r
353 {\r
354         struct rev_info *p_Rev;\r
355         p_Rev=(struct rev_info *)handle;\r
356 \r
357         return estimate_commit_count(p_Rev, p_Rev->commits);\r
358 }\r
359 \r
360 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit)\r
361 {\r
362         int ret =0;\r
363 \r
364         commit->m_pGitCommit = get_revision(handle);\r
365         if( commit->m_pGitCommit == NULL)\r
366                 return -2;\r
367         \r
368         ret=git_parse_commit(commit);\r
369         if(ret)\r
370                 return ret;\r
371 \r
372         return 0;\r
373 }\r
374 \r
375 int git_close_log(GIT_LOG handle)\r
376 {\r
377         if(handle)\r
378         {\r
379                 struct rev_info *p_Rev;\r
380                 p_Rev=(struct rev_info *)handle;\r
381                 if(p_Rev->pPrivate)\r
382                         free(p_Rev->pPrivate);\r
383                 free(handle);\r
384         }\r
385         \r
386         return 0;\r
387 }\r
388 \r
389 int git_open_diff(GIT_DIFF *diff, char * arg)\r
390 {\r
391         struct rev_info *p_Rev;\r
392         int size;\r
393         char ** argv=0;\r
394         int argc=0;\r
395                 \r
396         if(arg != NULL)\r
397                 argv = strtoargv(arg,&argc);\r
398 \r
399         p_Rev = malloc(sizeof(struct rev_info));\r
400         memset(p_Rev,0,sizeof(struct rev_info));\r
401 \r
402         p_Rev->pPrivate = argv;\r
403         *diff = (GIT_DIFF)p_Rev;\r
404 \r
405         init_revisions(p_Rev, g_prefix);\r
406         git_config(git_diff_basic_config, NULL); /* no "diff" UI options */\r
407         p_Rev->abbrev = 0;\r
408         p_Rev->diff = 1;\r
409         argc = setup_revisions(argc, argv, p_Rev, NULL);\r
410 \r
411         return 0;\r
412 }\r
413 int git_close_diff(GIT_DIFF handle)\r
414 {\r
415         git_diff_flush(handle);\r
416         if(handle)\r
417         {\r
418                 struct rev_info *p_Rev;\r
419                 p_Rev=(struct rev_info *)handle;\r
420                 if(p_Rev->pPrivate)\r
421                         free(p_Rev->pPrivate);\r
422                 free(handle);\r
423         }\r
424         return 0;\r
425 }\r
426 int git_diff_flush(GIT_DIFF diff)\r
427 {\r
428         struct diff_queue_struct *q = &diff_queued_diff;\r
429         struct rev_info *p_Rev;\r
430         int i;\r
431         p_Rev = (struct rev_info *)diff;\r
432         \r
433         if(q->nr == 0)\r
434                 return 0;\r
435 \r
436         for (i = 0; i < q->nr; i++)\r
437                 diff_free_filepair(q->queue[i]);\r
438 \r
439         if(q->queue)\r
440         {\r
441                 free(q->queue);\r
442                 q->queue = NULL;\r
443                 q->nr = q->alloc = 0;\r
444         }\r
445 \r
446         if (p_Rev->diffopt.close_file)\r
447                 fclose(p_Rev->diffopt.close_file);\r
448 \r
449         free_diffstat_info(&p_Rev->diffstat);\r
450 }\r
451 \r
452 int git_root_diff(GIT_DIFF diff, GIT_HASH hash,GIT_FILE *file, int *count)\r
453 {\r
454         int ret;\r
455         struct rev_info *p_Rev;\r
456         int i;\r
457         struct diff_queue_struct *q = &diff_queued_diff;\r
458 \r
459         p_Rev = (struct rev_info *)diff;\r
460 \r
461         ret=diff_root_tree_sha1(hash, "", &p_Rev->diffopt);\r
462 \r
463         if(ret)\r
464                 return ret;\r
465 \r
466         diffcore_std(&p_Rev->diffopt);\r
467 \r
468         memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));\r
469         for (i = 0; i < q->nr; i++) {\r
470                 struct diff_filepair *p = q->queue[i];\r
471                 //if (check_pair_status(p))\r
472                 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);\r
473         }\r
474 \r
475         if(file)\r
476                 *file = q;\r
477         if(count)\r
478                 *count = q->nr;\r
479 \r
480         return 0;\r
481 }\r
482 \r
483 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2, GIT_FILE * file, int *count)\r
484 {\r
485         struct rev_info *p_Rev;\r
486         int ret;\r
487         int i;\r
488         struct diff_queue_struct *q = &diff_queued_diff;\r
489         \r
490         p_Rev = (struct rev_info *)diff;\r
491 \r
492         ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);\r
493         if( ret )\r
494                 return ret;\r
495         \r
496         diffcore_std(&p_Rev->diffopt);\r
497 \r
498         memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));\r
499         for (i = 0; i < q->nr; i++) {\r
500                 struct diff_filepair *p = q->queue[i];\r
501                 //if (check_pair_status(p))\r
502                 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);\r
503         }\r
504 \r
505         if(file)\r
506                 *file = q;\r
507         if(count)\r
508                 *count = q->nr;\r
509         return 0;\r
510 }\r
511 \r
512 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
513 {\r
514         struct diff_queue_struct *q = &diff_queued_diff;\r
515         struct rev_info *p_Rev;\r
516         p_Rev = (struct rev_info *)diff;\r
517         \r
518         q = (struct diff_queue_struct *)file;\r
519         if(file == 0)\r
520                 return -1;\r
521         if(i>=q->nr)\r
522                 return -1;\r
523 \r
524         if(newname)\r
525                 *newname = q->queue[i]->two->path;\r
526 \r
527         if(oldname)\r
528                 *oldname = q->queue[i]->one->path;\r
529 \r
530         if(status)\r
531                 *status = q->queue[i]->status;\r
532 \r
533         if(p_Rev->diffstat.files)\r
534         {\r
535                 int j;\r
536                 for(j=0;j<p_Rev->diffstat.nr;j++)\r
537                 {\r
538                         if(strcmp(*newname,p_Rev->diffstat.files[j]->name)==0)\r
539                                 break;\r
540                 }\r
541                 if( j== p_Rev->diffstat.nr)\r
542                 {\r
543                         *IsBin=1;\r
544                         *inc=0;\r
545                         *dec=0;\r
546                         return 0;\r
547                 }\r
548                 if(IsBin)\r
549                         *IsBin = p_Rev->diffstat.files[j]->is_binary;\r
550                 if(inc)\r
551                         *inc = p_Rev->diffstat.files[j]->added;\r
552                 if(dec)\r
553                         *dec = p_Rev->diffstat.files[j]->deleted;\r
554         }else\r
555         {\r
556                 *IsBin=1;\r
557                 *inc=0;\r
558                 *dec=0;\r
559         }\r
560 \r
561         return 0;\r
562 }