OSDN Git Service

Add git diff support at gitdll
[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_free_commit(GIT_COMMIT *commit)\r
205 {\r
206         struct commit *p = commit->m_pGitCommit;\r
207 \r
208         if( p->parents)\r
209                 free_commit_list(p->parents);   \r
210 \r
211         if( p->buffer )\r
212         {\r
213                 free(p->buffer);\r
214         }\r
215         memset(commit,0,sizeof(GIT_COMMIT));\r
216         return 0;\r
217 }\r
218 \r
219 char **strtoargv(char *arg, int *size)\r
220 {\r
221         int count=0;\r
222         char *p=arg;\r
223         char **argv;\r
224         int i=0;\r
225         while(*p)\r
226         {\r
227                 if(*p == ' ')\r
228                         count ++;\r
229                 p++;\r
230         }\r
231         \r
232         argv=malloc(strlen(arg)+1 + (count +2)*sizeof(void*));\r
233         p=(char*)(argv+count+2);\r
234 \r
235         while(*arg)\r
236         {\r
237                 if(*arg == '"')\r
238                 {\r
239                         argv[i] = p;\r
240                         arg++;\r
241                         *p=*arg;\r
242                         while(*arg && *arg!= '"')\r
243                                 *p++=*arg++;\r
244                         *p++=0;\r
245                         arg++;\r
246                         i++;\r
247                         if(*arg == 0)\r
248                                 break;\r
249                 }\r
250                 if(*arg != ' ')\r
251                 {\r
252                         argv[i]=p;\r
253                         while(*arg && *arg !=' ')\r
254                                 *p++ = *arg++;\r
255                         i++;\r
256                         *p++=0;\r
257                 }\r
258                 arg++;\r
259         }\r
260         argv[i]=NULL;\r
261         *size = i;\r
262         return argv;\r
263 }\r
264 int git_open_log(GIT_LOG * handle, char * arg)\r
265 {\r
266         struct rev_info *p_Rev;\r
267         int size;\r
268         char ** argv=0;\r
269         int argc=0;\r
270         \r
271         if(arg != NULL)\r
272                 argv = strtoargv(arg,&argc);\r
273 \r
274         p_Rev = malloc(sizeof(struct rev_info));\r
275         memset(p_Rev,0,sizeof(struct rev_info));\r
276 \r
277         if(p_Rev == NULL)\r
278                 return -1;\r
279 \r
280         init_revisions(p_Rev, g_prefix);\r
281         p_Rev->diff = 1;\r
282         p_Rev->simplify_history = 0;\r
283         \r
284         cmd_log_init(argc, argv, g_prefix,p_Rev);\r
285 \r
286         p_Rev->pPrivate = argv;\r
287         *handle = p_Rev;\r
288         return 0;\r
289 \r
290 }\r
291 int git_get_log_firstcommit(GIT_LOG handle)\r
292 {\r
293         return prepare_revision_walk(handle);\r
294 }\r
295 \r
296 int git_get_log_nextcommit(GIT_LOG handle, GIT_COMMIT *commit)\r
297 {\r
298         int ret =0;\r
299 \r
300         commit->m_pGitCommit = get_revision(handle);\r
301         if( commit->m_pGitCommit == NULL)\r
302                 return -2;\r
303         \r
304         ret=git_parse_commit(commit);\r
305         if(ret)\r
306                 return ret;\r
307 \r
308         return 0;\r
309 }\r
310 \r
311 int git_close_log(GIT_LOG handle)\r
312 {\r
313         if(handle)\r
314         {\r
315                 struct rev_info *p_Rev;\r
316                 p_Rev=(struct rev_info *)handle;\r
317                 if(p_Rev->pPrivate)\r
318                         free(p_Rev->pPrivate);\r
319                 free(handle);\r
320         }\r
321         \r
322         return 0;\r
323 }\r
324 \r
325 int git_open_diff(GIT_DIFF *diff, char * arg)\r
326 {\r
327         struct rev_info *p_Rev;\r
328         int size;\r
329         char ** argv=0;\r
330         int argc=0;\r
331                 \r
332         if(arg != NULL)\r
333                 argv = strtoargv(arg,&argc);\r
334 \r
335         p_Rev = malloc(sizeof(struct rev_info));\r
336         memset(p_Rev,0,sizeof(struct rev_info));\r
337 \r
338         p_Rev->pPrivate = argv;\r
339         *diff = (GIT_DIFF)p_Rev;\r
340 \r
341         init_revisions(p_Rev, g_prefix);\r
342         git_config(git_diff_basic_config, NULL); /* no "diff" UI options */\r
343         p_Rev->abbrev = 0;\r
344         p_Rev->diff = 1;\r
345         argc = setup_revisions(argc, argv, p_Rev, NULL);\r
346 \r
347         return 0;\r
348 }\r
349 int git_diff_flush(struct diff_options *options)\r
350 {\r
351         struct diff_queue_struct *q = &diff_queued_diff;\r
352         int i;\r
353         for (i = 0; i < q->nr; i++)\r
354                 diff_free_filepair(q->queue[i]);\r
355 \r
356         if(q->queue)\r
357         {\r
358                 free(q->queue);\r
359                 q->queue = NULL;\r
360                 q->nr = q->alloc = 0;\r
361         }\r
362 \r
363         if (options->close_file)\r
364                 fclose(options->file);\r
365 \r
366 }\r
367 int git_diff(GIT_DIFF diff, GIT_HASH hash1, GIT_HASH hash2)\r
368 {\r
369         struct rev_info *p_Rev;\r
370         int ret;\r
371         int i;\r
372         struct diff_queue_struct *q = &diff_queued_diff;\r
373         \r
374         p_Rev = (struct rev_info *)diff;\r
375 \r
376         git_diff_flush(&p_Rev->diffopt);\r
377 \r
378         ret = diff_tree_sha1(hash1,hash2,"",&p_Rev->diffopt);\r
379         if( ret )\r
380                 return ret;\r
381         \r
382         diffcore_std(&p_Rev->diffopt);\r
383 \r
384         memset(&p_Rev->diffstat, 0, sizeof(struct diffstat_t));\r
385         for (i = 0; i < q->nr; i++) {\r
386                 struct diff_filepair *p = q->queue[i];\r
387                 if (check_pair_status(p))\r
388                                 diff_flush_stat(p, &p_Rev->diffopt, &p_Rev->diffstat);\r
389         }\r
390         free_diffstat_info(&p_Rev->diffstat);\r
391 \r
392         return 0;\r
393 }\r
394 \r