added index caching
[git/mingw/4msysgit/wingit-dll.git] / igit.c
blob8b42e30520496075899183ca0c81df98b94b4acf
1 // igit.c
2 //
4 #include <windows.h>
5 #include "igit.h"
6 #include "exec_cmd.h"
7 #include "git-compat-util.h"
8 #include "builtin.h"
9 #include "diff.h"
10 #include "revision.h"
11 #include <fcntl.h>
12 #include <stdlib.h>
15 #define IGIT_VERSION "0.1.0"
18 #define SAFE_FREE(_x) if (_x) { free(_x); _x = NULL; }
20 #define ASSERT(_x) //assert(_x)
23 static char l_sGitBinPath[2048];
26 /////////////////////////////////////////////////////////////////////
27 // Git utils
29 // GitCommandInit flags (mirrored from git.c)
30 #define RUN_SETUP (1<<0)
31 #define USE_PAGER (1<<1)
32 #define NEED_WORK_TREE (1<<2)
35 // GitCommandInit - does the basic init of run_command in git.c (returns path relative to project root)
36 static const char* GitCommandInit(int flags)
38 // simple init in main of git.c to set up git sys path
40 git_extract_argv0_path(l_sGitBinPath);
42 setup_path();
44 // init from run_command
46 const char *prefix = NULL;
48 if (flags & RUN_SETUP)
49 prefix = setup_git_directory();
51 if (flags & NEED_WORK_TREE)
52 setup_work_tree();
54 return prefix;
58 void fputsha1(LPBYTE sha1, FILE *fp)
60 int i;
61 for (i=0; i<20; i++)
63 fprintf(fp, "%02x", (UINT)*sha1++);
67 /////////////////////////////////////////////////////////////////////
68 // igInitPath
70 static LPSTR nextpath(LPCSTR src, LPSTR dst, UINT maxlen)
72 LPCSTR orgsrc;
74 while (*src == ';')
75 src++;
77 orgsrc = src;
79 if (!--maxlen)
80 goto nullterm;
82 while (*src && *src != ';')
84 if (*src != '"')
86 *dst++ = *src++;
87 if (!--maxlen)
89 orgsrc = src;
90 goto nullterm;
93 else
95 src++;
96 while (*src && *src != '"')
98 *dst++ = *src++;
99 if (!--maxlen)
101 orgsrc = src;
102 goto nullterm;
106 if (*src)
107 src++;
111 while (*src == ';')
112 src++;
114 nullterm:
116 *dst = 0;
118 return (orgsrc != src) ? (LPSTR)src : NULL;
121 static inline BOOL FileExists(LPCSTR lpszFileName)
123 struct stat st;
124 return lstat(lpszFileName, &st) == 0;
127 static BOOL FindGitPath()
129 char *env;
131 if ( !(env = getenv("PATH")) )
133 return FALSE;
136 char buf[_MAX_PATH];
138 const LPCSTR filename = "git.exe";
139 const int filelen = strlen(filename);
141 // search in all paths defined in PATH
142 while ((env = nextpath(env, buf, _MAX_PATH-1)) && *buf)
144 char *pfin = buf + strlen(buf)-1;
146 // ensure trailing slash
147 if (*pfin != '/' && *pfin != '\\')
148 strcpy(pfin+1, "\\");
150 const int len = strlen(buf);
152 if ((len + filelen) < _MAX_PATH)
153 strcpy(buf+len, filename);
154 else
155 break;
157 if ( FileExists(buf) )
159 // dir found
160 memcpy(l_sGitBinPath, buf, len);
161 l_sGitBinPath[len] = 0;
162 return TRUE;
166 return FALSE;
170 BOOL igInitPath(void)
172 if ( !FindGitPath() )
174 // fallback and use path of libiconv2.dll which wingit is linked to and normally is located in the git dir
175 if ( !GetModuleFileName(GetModuleHandle("libiconv2.dll"), l_sGitBinPath, sizeof(l_sGitBinPath)) )
177 OutputDebugString("[IGIT] Failed to locate Git/bin path\r\n");
178 return FALSE;
182 // slashify path to avoid mixing back and forward slashes (git uses forward)
183 char *p = l_sGitBinPath;
184 while (*p)
186 if (*p == '\\') *p = '/';
187 p++;
190 return TRUE;
194 /////////////////////////////////////////////////////////////////////
195 // igEnumFiles - based on builtin-ls-files
197 extern BOOL ig_enum_files(const char *pszProjectPath, const char *pszSubPath, const char *prefix, unsigned int nFlags);
200 int igEnumFiles(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags)
202 // clean up subpath
203 if (pszSubPath)
205 int len = strlen(pszSubPath);
207 //char *s = alloca(len+1);
208 //strcpy(s, pszSubPath);
209 char *s = strdup(pszSubPath);
211 // slashify
212 char *p = s;
213 while (*p)
215 if (*p == '\\') *p = '/';
216 p++;
219 // remove trailing slashes
220 char *c = &s[len-1];
221 while (*c == '/' && c > s) *c-- = 0;
222 // remove initial slashes
223 while (*s == '/') s++;
225 pszSubPath = *s ? s : NULL;
228 const char *prefix = GitCommandInit(RUN_SETUP);
230 if ( !ig_enum_files(pszProjectPath, pszSubPath, prefix, nFlags) )
232 return -1;
235 return 0;
239 /////////////////////////////////////////////////////////////////////
240 // igGetRevisionID
242 int igGetRevisionID(const char *pszName)
244 BYTE sha1[20];
246 GitCommandInit(0);
248 git_config(git_default_config, NULL);
250 if ( !get_sha1(pszName, sha1) )
252 fputsha1(sha1, stdout);
253 fputc(0, stdout);
255 return 0;
258 return -1;
262 /////////////////////////////////////////////////////////////////////
263 // main
265 int main(int argc, const char **argv)
267 if (argc < 3)
269 if (argc == 2 && !strcasecmp(argv[1], "version"))
271 fputs(IGIT_VERSION, stdout);
272 fputc(0, stdout);
273 return 0;
276 fputs("igit v"IGIT_VERSION" - backend interface to git intended for use by frontends\n\n", stderr);
277 fputs("usage: igit <project path> <command> [params]*\n", stderr);
278 fputs(" igit version\n\n", stderr);
279 fputs("commands:\n", stderr);
280 fputs(" revision [name] SHA1 for specified commit or HEAD if none\n", stderr);
281 fputs(" status [flags [sub path]] list working copy files with status\n", stderr);
282 fputs(" flags: CdDefrs-\n", stderr);
283 return -1;
286 if ( !igInitPath() )
288 return -1;
291 //if (argv[0] && *argv[0])
292 // git_extract_argv0_path(argv[0]);
293 git_extract_argv0_path(l_sGitBinPath);
295 argv++;
296 argc--;
298 // get project path
300 const char *projpath = argv[0];
302 if ( chdir(projpath) )
303 return -1;
305 argv++;
306 argc--;
308 // get command
310 const char *cmd = argv[0];
312 argv++;
313 argc--;
315 // process command
317 int res = 0;
319 if ( !strcasecmp(cmd, "revision") )
321 const char *name = argc ? argv[0] : "HEAD";
323 res = igGetRevisionID(name);
325 else if ( !strcasecmp(cmd, "status") )
327 UINT nFlags = 0;
328 LPCSTR pszSubPath = NULL;
330 if (argc)
332 LPCSTR q = argv[0];
333 while (*q)
335 switch (*q++)
337 case 'd': nFlags |= WGEFF_DirStatusDelta; break;
338 case 'D': nFlags |= WGEFF_DirStatusAll; break;
339 case 'e': nFlags |= WGEFF_EmptyAsNormal; break;
340 case 'f': nFlags |= WGEFF_FullPath; break;
341 case 'r': nFlags |= WGEFF_NoRecurse; break;
342 case 's': nFlags |= WGEFF_SingleFile; break;
343 case 'C': nFlags |= WGEFF_NoCacheIndex; break;
347 if (argc > 1)
348 pszSubPath = argv[1];
351 res = igEnumFiles(projpath, pszSubPath, nFlags);
354 return res;