help.con commit remove unused/unneeded "pattern" argument of list_commands (edb6ddc)
   1/*
   2 * builtin-help.c
   3 *
   4 * Builtin help-related commands (help, usage, version)
   5 */
   6#include "cache.h"
   7#include "builtin.h"
   8#include "exec_cmd.h"
   9#include "common-cmds.h"
  10#include <sys/ioctl.h>
  11
  12/* most GUI terminals set COLUMNS (although some don't export it) */
  13static int term_columns(void)
  14{
  15        char *col_string = getenv("COLUMNS");
  16        int n_cols;
  17
  18        if (col_string && (n_cols = atoi(col_string)) > 0)
  19                return n_cols;
  20
  21#ifdef TIOCGWINSZ
  22        {
  23                struct winsize ws;
  24                if (!ioctl(1, TIOCGWINSZ, &ws)) {
  25                        if (ws.ws_col)
  26                                return ws.ws_col;
  27                }
  28        }
  29#endif
  30
  31        return 80;
  32}
  33
  34static inline void mput_char(char c, unsigned int num)
  35{
  36        while(num--)
  37                putchar(c);
  38}
  39
  40static struct cmdname {
  41        size_t len;
  42        char name[1];
  43} **cmdname;
  44static int cmdname_alloc, cmdname_cnt;
  45
  46static void add_cmdname(const char *name, int len)
  47{
  48        struct cmdname *ent;
  49        if (cmdname_alloc <= cmdname_cnt) {
  50                cmdname_alloc = cmdname_alloc + 200;
  51                cmdname = xrealloc(cmdname, cmdname_alloc * sizeof(*cmdname));
  52        }
  53        ent = xmalloc(sizeof(*ent) + len);
  54        ent->len = len;
  55        memcpy(ent->name, name, len);
  56        ent->name[len] = 0;
  57        cmdname[cmdname_cnt++] = ent;
  58}
  59
  60static int cmdname_compare(const void *a_, const void *b_)
  61{
  62        struct cmdname *a = *(struct cmdname **)a_;
  63        struct cmdname *b = *(struct cmdname **)b_;
  64        return strcmp(a->name, b->name);
  65}
  66
  67static void pretty_print_string_list(struct cmdname **cmdname, int longest)
  68{
  69        int cols = 1, rows;
  70        int space = longest + 1; /* min 1 SP between words */
  71        int max_cols = term_columns() - 1; /* don't print *on* the edge */
  72        int i, j;
  73
  74        if (space < max_cols)
  75                cols = max_cols / space;
  76        rows = (cmdname_cnt + cols - 1) / cols;
  77
  78        qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
  79
  80        for (i = 0; i < rows; i++) {
  81                printf("  ");
  82
  83                for (j = 0; j < cols; j++) {
  84                        int n = j * rows + i;
  85                        int size = space;
  86                        if (n >= cmdname_cnt)
  87                                break;
  88                        if (j == cols-1 || n + rows >= cmdname_cnt)
  89                                size = 1;
  90                        printf("%-*s", size, cmdname[n]->name);
  91                }
  92                putchar('\n');
  93        }
  94}
  95
  96static void list_commands(const char *exec_path)
  97{
  98        unsigned int longest = 0;
  99        char path[PATH_MAX];
 100        const char *prefix = "git-";
 101        int prefix_len = strlen(prefix);
 102        int dirlen;
 103        DIR *dir = opendir(exec_path);
 104        struct dirent *de;
 105
 106        if (!dir) {
 107                fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno));
 108                exit(1);
 109        }
 110
 111        dirlen = strlen(exec_path);
 112        if (PATH_MAX - 20 < dirlen) {
 113                fprintf(stderr, "git: insanely long exec-path '%s'\n",
 114                        exec_path);
 115                exit(1);
 116        }
 117
 118        memcpy(path, exec_path, dirlen);
 119        path[dirlen++] = '/';
 120
 121        while ((de = readdir(dir)) != NULL) {
 122                struct stat st;
 123                int entlen;
 124
 125                if (prefixcmp(de->d_name, prefix))
 126                        continue;
 127                strcpy(path+dirlen, de->d_name);
 128                if (stat(path, &st) || /* stat, not lstat */
 129                    !S_ISREG(st.st_mode) ||
 130                    !(st.st_mode & S_IXUSR))
 131                        continue;
 132
 133                entlen = strlen(de->d_name) - prefix_len;
 134                if (has_extension(de->d_name, ".exe"))
 135                        entlen -= 4;
 136
 137                if (longest < entlen)
 138                        longest = entlen;
 139
 140                add_cmdname(de->d_name + prefix_len, entlen);
 141        }
 142        closedir(dir);
 143
 144        printf("git commands available in '%s'\n", exec_path);
 145        printf("----------------------------");
 146        mput_char('-', strlen(exec_path));
 147        putchar('\n');
 148        pretty_print_string_list(cmdname, longest);
 149        putchar('\n');
 150}
 151
 152void list_common_cmds_help(void)
 153{
 154        int i, longest = 0;
 155
 156        for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
 157                if (longest < strlen(common_cmds[i].name))
 158                        longest = strlen(common_cmds[i].name);
 159        }
 160
 161        puts("The most commonly used git commands are:");
 162        for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
 163                printf("   %s   ", common_cmds[i].name);
 164                mput_char(' ', longest - strlen(common_cmds[i].name));
 165                puts(common_cmds[i].help);
 166        }
 167        puts("(use 'git help -a' to get a list of all installed git commands)");
 168}
 169
 170static void show_man_page(const char *git_cmd)
 171{
 172        const char *page;
 173
 174        if (!prefixcmp(git_cmd, "git"))
 175                page = git_cmd;
 176        else {
 177                int page_len = strlen(git_cmd) + 4;
 178                char *p = xmalloc(page_len + 1);
 179                strcpy(p, "git-");
 180                strcpy(p + 4, git_cmd);
 181                p[page_len] = 0;
 182                page = p;
 183        }
 184
 185        execlp("man", "man", page, NULL);
 186}
 187
 188void help_unknown_cmd(const char *cmd)
 189{
 190        fprintf(stderr, "git: '%s' is not a git-command. See 'git --help'.\n", cmd);
 191        exit(1);
 192}
 193
 194int cmd_version(int argc, const char **argv, const char *prefix)
 195{
 196        printf("git version %s\n", git_version_string);
 197        return 0;
 198}
 199
 200int cmd_help(int argc, const char **argv, const char *prefix)
 201{
 202        const char *help_cmd = argc > 1 ? argv[1] : NULL;
 203        const char *exec_path = git_exec_path();
 204
 205        if (!help_cmd) {
 206                printf("usage: %s\n\n", git_usage_string);
 207                list_common_cmds_help();
 208                exit(0);
 209        }
 210
 211        else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) {
 212                printf("usage: %s\n\n", git_usage_string);
 213                if(exec_path)
 214                        list_commands(exec_path);
 215                exit(0);
 216        }
 217
 218        else
 219                show_man_page(help_cmd);
 220
 221        return 0;
 222}