#include #include #include #include #include #include #include #include #ifndef PATH_MAX # define PATH_MAX 4096 #endif static const char git_usage[] = "Usage: git [ --version ] [ --lib= ] COMMAND [ OPTIONS ] [ TARGET ]"; struct string_list { size_t len; char *str; struct string_list *next; }; /* most gui terms set COLUMNS (although some don't export it) */ static int columns(void) { char *col_string = getenv("COLUMNS"); int n_cols = 0; if (col_string && (n_cols = atoi(col_string)) > 0) return n_cols; return 80; } static inline void mput_char(char c, unsigned int num) { unsigned int i; for(i = 0; i < num; i++) putchar(c); } static void fmt_print_string_list(struct string_list *list, int longest) { int cols; int space = longest + 1; /* space between start of string1 and string2 */ int max_cols = columns() - 1; cols = max_cols / space; if(cols < 1) { cols = 1; space = 0; } while (list) { int c = cols; printf(" "); for(c = cols; c; c--) { if (!list) break; printf("%s", list->str); if (space && c != 1) mput_char(' ', space - list->len); list = list->next; } putchar('\n'); } } static void usage(char *path, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3))); static void usage(char *path, const char *fmt, ...) { struct string_list *list, *tail; unsigned int longest = 0, i; glob_t gl; list = tail = NULL; if (!fmt) puts(git_usage); else { printf("git: "); va_list ap; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); } putchar('\n'); if (!path) exit(1); if (chdir(path) < 0) { printf("git: '%s': %s\n", path, strerror(errno)); exit(1); } printf("\ngit commands available in '%s'\n", path); printf("----------------------------"); mput_char('-', strlen(path)); putchar('\n'); glob("git-*", 0, NULL, &gl); for (i = 0; i < gl.gl_pathc; i++) { int len = strlen(gl.gl_pathv[i] + 4); if(access(gl.gl_pathv[i], X_OK)) continue; if (longest < len) longest = len; if (!tail) tail = list = malloc(sizeof(struct string_list)); else { tail->next = malloc(sizeof(struct string_list)); tail = tail->next; } tail->len = len; tail->str = gl.gl_pathv[i] + 4; tail->next = NULL; } fmt_print_string_list(list, longest); puts("\nman-pages can be reached through 'man git-'\n"); exit(1); } #define DEFAULT_GIT_LIB "/usr/bin" #define GIT_VERSION "0.99.9.GIT" int main(int argc, char **argv, char **envp) { char git_command[PATH_MAX + 1]; char *git_lib = getenv("GIT_LIB"); char wd[PATH_MAX + 1], libdir[PATH_MAX + 1]; getcwd(wd, PATH_MAX); if(argc == 1) { if (git_lib) usage(git_lib, NULL); usage(DEFAULT_GIT_LIB, NULL); } argv++; /* always *argv since we inc it if we hit an option */ while (argc-- && !strncmp(*argv, "--", 2)) { char *arg = (*argv++) + 2; if (!strncmp(arg, "lib=", 3)) git_lib = arg + 4; else if (!strncmp(arg, "version", 7)) { printf("git version %s\n", GIT_VERSION); exit(0); } else usage (NULL, NULL); } if (!git_lib) git_lib = DEFAULT_GIT_LIB; /* allow relative paths, but run with exact */ if (chdir(git_lib)) { printf("git: '%s': %s\n", git_lib, strerror(errno)); exit (1); } getcwd(libdir, sizeof(libdir)); chdir(wd); snprintf(git_command, sizeof(git_command), "%s/git-%s", libdir, *argv); if (access(git_command, X_OK)) usage(git_lib, "'%s' is not a git-command", *argv); if (execve(git_command, argv, envp)) { printf("Failed to run command '%s': %s\n", git_command, strerror(errno)); return 1; } /* not reached */ return 0; }