perf tools: Move help_unknown_cmd() to its own file
[deliverable/linux.git] / tools / perf / util / help.c
CommitLineData
07800601 1#include "cache.h"
148be2c1 2#include "../builtin.h"
07800601 3#include "exec_cmd.h"
07800601
IM
4#include "help.h"
5
f37a291c 6void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
07800601
IM
7{
8 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
9
10 ent->len = len;
11 memcpy(ent->name, name, len);
12 ent->name[len] = 0;
13
14 ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
15 cmds->names[cmds->cnt++] = ent;
16}
17
5feaac24 18void clean_cmdnames(struct cmdnames *cmds)
07800601 19{
f37a291c
IM
20 unsigned int i;
21
07800601 22 for (i = 0; i < cmds->cnt; ++i)
74cf249d
ACM
23 zfree(&cmds->names[i]);
24 zfree(&cmds->names);
07800601
IM
25 cmds->cnt = 0;
26 cmds->alloc = 0;
27}
28
5feaac24 29int cmdname_compare(const void *a_, const void *b_)
07800601
IM
30{
31 struct cmdname *a = *(struct cmdname **)a_;
32 struct cmdname *b = *(struct cmdname **)b_;
33 return strcmp(a->name, b->name);
34}
35
5feaac24 36void uniq(struct cmdnames *cmds)
07800601 37{
f37a291c 38 unsigned int i, j;
07800601
IM
39
40 if (!cmds->cnt)
41 return;
42
43 for (i = j = 1; i < cmds->cnt; i++)
44 if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
45 cmds->names[j++] = cmds->names[i];
46
47 cmds->cnt = j;
48}
49
50void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
51{
f37a291c 52 size_t ci, cj, ei;
07800601
IM
53 int cmp;
54
55 ci = cj = ei = 0;
56 while (ci < cmds->cnt && ei < excludes->cnt) {
57 cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
58 if (cmp < 0)
59 cmds->names[cj++] = cmds->names[ci++];
60 else if (cmp == 0)
61 ci++, ei++;
62 else if (cmp > 0)
63 ei++;
64 }
65
66 while (ci < cmds->cnt)
67 cmds->names[cj++] = cmds->names[ci++];
68
69 cmds->cnt = cj;
70}
71
72static void pretty_print_string_list(struct cmdnames *cmds, int longest)
73{
74 int cols = 1, rows;
75 int space = longest + 1; /* min 1 SP between words */
a41794cd
ACM
76 struct winsize win;
77 int max_cols;
07800601
IM
78 int i, j;
79
a41794cd
ACM
80 get_term_dimensions(&win);
81 max_cols = win.ws_col - 1; /* don't print *on* the edge */
82
07800601
IM
83 if (space < max_cols)
84 cols = max_cols / space;
85 rows = (cmds->cnt + cols - 1) / cols;
86
87 for (i = 0; i < rows; i++) {
88 printf(" ");
89
90 for (j = 0; j < cols; j++) {
f37a291c
IM
91 unsigned int n = j * rows + i;
92 unsigned int size = space;
93
07800601
IM
94 if (n >= cmds->cnt)
95 break;
96 if (j == cols-1 || n + rows >= cmds->cnt)
97 size = 1;
98 printf("%-*s", size, cmds->names[n]->name);
99 }
100 putchar('\n');
101 }
102}
103
104static int is_executable(const char *name)
105{
106 struct stat st;
107
108 if (stat(name, &st) || /* stat, not lstat */
109 !S_ISREG(st.st_mode))
110 return 0;
111
07800601
IM
112 return st.st_mode & S_IXUSR;
113}
114
115static void list_commands_in_dir(struct cmdnames *cmds,
116 const char *path,
117 const char *prefix)
118{
119 int prefix_len;
120 DIR *dir = opendir(path);
121 struct dirent *de;
122 struct strbuf buf = STRBUF_INIT;
123 int len;
124
125 if (!dir)
126 return;
127 if (!prefix)
128 prefix = "perf-";
129 prefix_len = strlen(prefix);
130
131 strbuf_addf(&buf, "%s/", path);
132 len = buf.len;
133
134 while ((de = readdir(dir)) != NULL) {
135 int entlen;
136
137 if (prefixcmp(de->d_name, prefix))
138 continue;
139
140 strbuf_setlen(&buf, len);
141 strbuf_addstr(&buf, de->d_name);
142 if (!is_executable(buf.buf))
143 continue;
144
145 entlen = strlen(de->d_name) - prefix_len;
146 if (has_extension(de->d_name, ".exe"))
147 entlen -= 4;
148
149 add_cmdname(cmds, de->d_name + prefix_len, entlen);
150 }
151 closedir(dir);
152 strbuf_release(&buf);
153}
154
155void load_command_list(const char *prefix,
156 struct cmdnames *main_cmds,
157 struct cmdnames *other_cmds)
158{
159 const char *env_path = getenv("PATH");
c4068f51 160 char *exec_path = perf_exec_path();
07800601
IM
161
162 if (exec_path) {
163 list_commands_in_dir(main_cmds, exec_path, prefix);
164 qsort(main_cmds->names, main_cmds->cnt,
165 sizeof(*main_cmds->names), cmdname_compare);
166 uniq(main_cmds);
167 }
168
169 if (env_path) {
170 char *paths, *path, *colon;
171 path = paths = strdup(env_path);
172 while (1) {
173 if ((colon = strchr(path, PATH_SEP)))
174 *colon = 0;
175 if (!exec_path || strcmp(path, exec_path))
176 list_commands_in_dir(other_cmds, path, prefix);
177
178 if (!colon)
179 break;
180 path = colon + 1;
181 }
182 free(paths);
183
184 qsort(other_cmds->names, other_cmds->cnt,
185 sizeof(*other_cmds->names), cmdname_compare);
186 uniq(other_cmds);
187 }
c4068f51 188 free(exec_path);
07800601
IM
189 exclude_cmds(other_cmds, main_cmds);
190}
191
192void list_commands(const char *title, struct cmdnames *main_cmds,
193 struct cmdnames *other_cmds)
194{
f37a291c 195 unsigned int i, longest = 0;
07800601
IM
196
197 for (i = 0; i < main_cmds->cnt; i++)
198 if (longest < main_cmds->names[i]->len)
199 longest = main_cmds->names[i]->len;
200 for (i = 0; i < other_cmds->cnt; i++)
201 if (longest < other_cmds->names[i]->len)
202 longest = other_cmds->names[i]->len;
203
204 if (main_cmds->cnt) {
c4068f51 205 char *exec_path = perf_exec_path();
07800601
IM
206 printf("available %s in '%s'\n", title, exec_path);
207 printf("----------------");
208 mput_char('-', strlen(title) + strlen(exec_path));
209 putchar('\n');
210 pretty_print_string_list(main_cmds, longest);
211 putchar('\n');
c4068f51 212 free(exec_path);
07800601
IM
213 }
214
215 if (other_cmds->cnt) {
216 printf("%s available from elsewhere on your $PATH\n", title);
217 printf("---------------------------------------");
218 mput_char('-', strlen(title));
219 putchar('\n');
220 pretty_print_string_list(other_cmds, longest);
221 putchar('\n');
222 }
223}
224
225int is_in_cmdlist(struct cmdnames *c, const char *s)
226{
f37a291c
IM
227 unsigned int i;
228
07800601
IM
229 for (i = 0; i < c->cnt; i++)
230 if (!strcmp(s, c->names[i]->name))
231 return 1;
232 return 0;
233}
This page took 0.3176 seconds and 5 git commands to generate.