1 // SPDX-License-Identifier: GPL-2.0
4 #include <sys/ttydefaults.h>
6 #include "../../util/sort.h"
7 #include "../../util/util.h"
8 #include "../../util/hist.h"
9 #include "../../util/debug.h"
10 #include "../../util/symbol.h"
11 #include "../browser.h"
12 #include "../helpline.h"
13 #include "../libslang.h"
15 /* 2048 lines should be enough for a script output */
16 #define MAX_LINES 2048
18 /* 160 bytes for one output line */
19 #define AVERAGE_LINE_LEN 160
22 struct list_head node
;
23 char line
[AVERAGE_LINE_LEN
];
26 struct perf_script_browser
{
28 struct list_head entries
;
29 const char *script_name
;
33 #define SCRIPT_NAMELEN 128
34 #define SCRIPT_MAX_NO 64
36 * Usually the full path for a script is:
37 * /home/username/libexec/perf-core/scripts/python/xxx.py
38 * /home/username/libexec/perf-core/scripts/perl/xxx.pl
39 * So 256 should be long enough to contain the full path.
41 #define SCRIPT_FULLPATH_LEN 256
44 * When success, will copy the full path of the selected script
45 * into the buffer pointed by script_name, and return 0.
46 * Return -1 on failure.
48 static int list_scripts(char *script_name
)
50 char *buf
, *names
[SCRIPT_MAX_NO
], *paths
[SCRIPT_MAX_NO
];
51 int i
, num
, choice
, ret
= -1;
53 /* Preset the script name to SCRIPT_NAMELEN */
54 buf
= malloc(SCRIPT_MAX_NO
* (SCRIPT_NAMELEN
+ SCRIPT_FULLPATH_LEN
));
58 for (i
= 0; i
< SCRIPT_MAX_NO
; i
++) {
59 names
[i
] = buf
+ i
* (SCRIPT_NAMELEN
+ SCRIPT_FULLPATH_LEN
);
60 paths
[i
] = names
[i
] + SCRIPT_NAMELEN
;
63 num
= find_scripts(names
, paths
);
65 choice
= ui__popup_menu(num
, names
);
66 if (choice
< num
&& choice
>= 0) {
67 strcpy(script_name
, paths
[choice
]);
76 static void script_browser__write(struct ui_browser
*browser
,
79 struct script_line
*sline
= list_entry(entry
, struct script_line
, node
);
80 bool current_entry
= ui_browser__is_current_entry(browser
, row
);
82 ui_browser__set_color(browser
, current_entry
? HE_COLORSET_SELECTED
:
85 ui_browser__write_nstring(browser
, sline
->line
, browser
->width
);
88 static int script_browser__run(struct perf_script_browser
*browser
)
92 if (ui_browser__show(&browser
->b
, browser
->script_name
,
93 "Press ESC to exit") < 0)
97 key
= ui_browser__run(&browser
->b
, 0);
99 /* We can add some special key handling here if needed */
103 ui_browser__hide(&browser
->b
);
108 int script_browse(const char *script_opt
)
110 char cmd
[SCRIPT_FULLPATH_LEN
*2], script_name
[SCRIPT_FULLPATH_LEN
];
114 int ret
= -1, nr_entries
= 0;
117 struct script_line
*sline
;
119 struct perf_script_browser script
= {
121 .refresh
= ui_browser__list_head_refresh
,
122 .seek
= ui_browser__list_head_seek
,
123 .write
= script_browser__write
,
125 .script_name
= script_name
,
128 INIT_LIST_HEAD(&script
.entries
);
130 /* Save each line of the output in one struct script_line object. */
131 buf
= zalloc((sizeof(*sline
)) * MAX_LINES
);
136 memset(script_name
, 0, SCRIPT_FULLPATH_LEN
);
137 if (list_scripts(script_name
))
140 sprintf(cmd
, "perf script -s %s ", script_name
);
143 strcat(cmd
, script_opt
);
147 strcat(cmd
, input_name
);
150 strcat(cmd
, " 2>&1");
152 fp
= popen(cmd
, "r");
156 while ((retlen
= getline(&line
, &len
, fp
)) != -1) {
157 strncpy(sline
->line
, line
, AVERAGE_LINE_LEN
);
159 /* If one output line is very large, just cut it short */
160 if (retlen
>= AVERAGE_LINE_LEN
) {
161 sline
->line
[AVERAGE_LINE_LEN
- 1] = '\0';
162 sline
->line
[AVERAGE_LINE_LEN
- 2] = '\n';
164 list_add_tail(&sline
->node
, &script
.entries
);
166 if (script
.b
.width
< retlen
)
167 script
.b
.width
= retlen
;
169 if (nr_entries
++ >= MAX_LINES
- 1)
174 if (script
.b
.width
> AVERAGE_LINE_LEN
)
175 script
.b
.width
= AVERAGE_LINE_LEN
;
180 script
.nr_lines
= nr_entries
;
181 script
.b
.nr_entries
= nr_entries
;
182 script
.b
.entries
= &script
.entries
;
184 ret
= script_browser__run(&script
);