1 /*
2  *      Copyright 2007-2011 Frank Lanitz <frank(at)frank(dot)uvena(dot)de>
3  *      Copyright 2007-2009 Enrico Tröger <enrico.troeger@uvena.de>
4  *      Copyright 2007 Nick Treleaven <nick.treleaven@btinternet.com>
5  *      Copyright 2007-2009 Yura Siamashka <yurand2@gmail.com>
6  *
7  *      This program is free software; you can redistribute it and/or modify
8  *      it under the terms of the GNU General Public License as published by
9  *      the Free Software Foundation; either version 2 of the License, or
10  *      (at your option) any later version.
11  *
12  *      This program is distributed in the hope that it will be useful,
13  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *      GNU General Public License for more details.
16  *
17  *      You should have received a copy of the GNU General Public License
18  *      along with this program; if not, write to the Free Software
19  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #include <string.h>
23 #include <geanyplugin.h>
24 #include "geanyvc.h"
25 
26 extern GeanyData *geany_data;
27 
28 
29 static const gchar *SVK_CMD_DIFF_FILE[] = { "svk", "diff", ABS_FILENAME, NULL };
30 static const gchar *SVK_CMD_DIFF_DIR[] = { "svk", "diff", ABS_DIRNAME, NULL };
31 static const gchar *SVK_CMD_REVERT_FILE[] = { "svk", "revert", BASENAME, NULL };
32 static const gchar *SVK_CMD_REVERT_DIR[] = { "svk", "revert", "--recursive", BASE_DIRNAME, NULL };
33 static const gchar *SVK_CMD_STATUS[] = { "svk", "status", NULL };
34 static const gchar *SVK_CMD_ADD[] = { "svk", "add", BASENAME, NULL };
35 static const gchar *SVK_CMD_REMOVE[] = { "svk", "remove", BASENAME, NULL };
36 static const gchar *SVK_CMD_LOG_FILE[] = { "svk", "log", BASENAME, NULL };
37 static const gchar *SVK_CMD_LOG_DIR[] = { "svk", "log", ABS_DIRNAME, NULL };
38 static const gchar *SVK_CMD_COMMIT[] = { "svk", "commit", "-m", MESSAGE, FILE_LIST, NULL };
39 static const gchar *SVK_CMD_BLAME[] = { "svk", "blame", BASENAME, NULL };
40 static const gchar *SVK_CMD_SHOW[] = { "svk", "cat", BASENAME, NULL };
41 static const gchar *SVK_CMD_UPDATE[] = { "svk", "up", NULL };
42 
43 static const VC_COMMAND commands[] = {
44 	{
45 		VC_COMMAND_STARTDIR_FILE,
46 		SVK_CMD_DIFF_FILE,
47 		NULL,
48 		NULL},
49 	{
50 		VC_COMMAND_STARTDIR_FILE,
51 		SVK_CMD_DIFF_DIR,
52 		NULL,
53 		NULL},
54 	{
55 		VC_COMMAND_STARTDIR_FILE,
56 		SVK_CMD_REVERT_FILE,
57 		NULL,
58 		NULL},
59 	{
60 		VC_COMMAND_STARTDIR_BASE,
61 		SVK_CMD_REVERT_DIR,
62 		NULL,
63 		NULL},
64 	{
65 		VC_COMMAND_STARTDIR_FILE,
66 		SVK_CMD_STATUS,
67 		NULL,
68 		NULL},
69 	{
70 		VC_COMMAND_STARTDIR_FILE,
71 		SVK_CMD_ADD,
72 		NULL,
73 		NULL},
74 	{
75 		VC_COMMAND_STARTDIR_FILE,
76 		SVK_CMD_REMOVE,
77 		NULL,
78 		NULL},
79 	{
80 		VC_COMMAND_STARTDIR_FILE,
81 		SVK_CMD_LOG_FILE,
82 		NULL,
83 		NULL},
84 	{
85 		VC_COMMAND_STARTDIR_FILE,
86 		SVK_CMD_LOG_DIR,
87 		NULL,
88 		NULL},
89 	{
90 		VC_COMMAND_STARTDIR_FILE,
91 		SVK_CMD_COMMIT,
92 		NULL,
93 		NULL},
94 	{
95 		VC_COMMAND_STARTDIR_FILE,
96 		SVK_CMD_BLAME,
97 		NULL,
98 		NULL},
99 	{
100 		VC_COMMAND_STARTDIR_FILE,
101 		SVK_CMD_SHOW,
102 		NULL,
103 		NULL},
104 	{
105 		VC_COMMAND_STARTDIR_BASE,
106 		SVK_CMD_UPDATE,
107 		NULL,
108 		NULL}
109 };
110 
111 
112 static gchar *
get_base_dir(const gchar * path)113 get_base_dir(const gchar * path)
114 {
115 	/* NOT IMPLEMENTED */
116 	return g_path_get_dirname(path);
117 }
118 
119 static gboolean
in_vc_svk(const gchar * filename)120 in_vc_svk(const gchar * filename)
121 {
122 	gint exit_code;
123 	const gchar *argv[] = { "svk", "info", NULL, NULL };
124 	gchar *dir;
125 	gchar *base_name = NULL;
126 	gboolean ret = FALSE;
127 
128 
129 	if (g_file_test(filename, G_FILE_TEST_IS_DIR))
130 	{
131 		exit_code =
132 			execute_custom_command(filename, (const gchar **) argv, NULL, NULL, NULL,
133 					       filename, NULL, NULL);
134 
135 	}
136 	else
137 	{
138 		base_name = g_path_get_basename(filename);
139 		dir = g_path_get_dirname(filename);
140 
141 		argv[2] = base_name;
142 
143 		exit_code = execute_custom_command(dir, (const gchar **) argv, NULL, NULL, NULL,
144 						   dir, NULL, NULL);
145 
146 		g_free(dir);
147 		g_free(base_name);
148 	}
149 
150 	if (exit_code == 0)
151 	{
152 		ret = TRUE;
153 	}
154 
155 	return ret;
156 }
157 
158 static GSList *
get_commit_files_svk(const gchar * dir)159 get_commit_files_svk(const gchar * dir)
160 {
161 	enum
162 	{
163 		FIRST_CHAR,
164 		SKIP_SPACE,
165 		FILE_NAME,
166 	};
167 
168 	gchar *txt;
169 	GSList *ret = NULL;
170 	gint pstatus = FIRST_CHAR;
171 	const gchar *p;
172 	gchar *base_name;
173 	const gchar *start = NULL;
174 	CommitItem *item;
175 
176 	const gchar *status = NULL;
177 	gchar *filename;
178 	const char *argv[] = { "svk", "status", NULL };
179 
180 	execute_custom_command(dir, argv, NULL, &txt, NULL, dir, NULL, NULL);
181 	if (EMPTY(txt))
182 		return NULL;
183 	p = txt;
184 
185 	while (*p)
186 	{
187 		if (*p == '\r')
188 		{
189 		}
190 		else if (pstatus == FIRST_CHAR)
191 		{
192 			status = NULL;
193 			if (*p == '?')
194 				status = FILE_STATUS_UNKNOWN;
195 			else if (*p == 'M')
196 				status = FILE_STATUS_MODIFIED;
197 			else if (*p == 'D')
198 				status = FILE_STATUS_DELETED;
199 			else if (*p == 'A')
200 				status = FILE_STATUS_ADDED;
201 
202 			if (!status || *(p + 1) != ' ')
203 			{
204 				/* skip unknown status line */
205 				while (*p)
206 				{
207 					p++;
208 					if (*p == '\n')
209 					{
210 						p++;
211 						break;
212 					}
213 				}
214 				pstatus = FIRST_CHAR;
215 				continue;
216 			}
217 			pstatus = SKIP_SPACE;
218 		}
219 		else if (pstatus == SKIP_SPACE)
220 		{
221 			if (*p == ' ' || *p == '\t')
222 			{
223 			}
224 			else
225 			{
226 				start = p;
227 				pstatus = FILE_NAME;
228 			}
229 		}
230 		else if (pstatus == FILE_NAME)
231 		{
232 			if (*p == '\n')
233 			{
234 				if (status != FILE_STATUS_UNKNOWN)
235 				{
236 					base_name = g_malloc0(p - start + 1);
237 					memcpy(base_name, start, p - start);
238 					filename = g_build_filename(dir, base_name, NULL);
239 					g_free(base_name);
240 					item = g_new(CommitItem, 1);
241 					item->status = status;
242 					item->path = filename;
243 					ret = g_slist_append(ret, item);
244 				}
245 				pstatus = FIRST_CHAR;
246 			}
247 		}
248 		p++;
249 	}
250 	g_free(txt);
251 	return ret;
252 }
253 
254 VC_RECORD VC_SVK = {
255 	commands,
256 	"svk",
257 	get_base_dir,
258 	in_vc_svk,
259 	get_commit_files_svk,
260 };
261