NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
dump.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <limits.h>
32#include <stdbool.h>
33#include <stdint.h>
34#include <stdio.h>
35#include <string.h>
36#include <wchar.h>
37#include "mutt/lib.h"
38#include "core/lib.h"
39#include "gui/lib.h"
40#include "lib.h"
41#include "menu/lib.h"
42#include "pager/lib.h"
43#include "parse/lib.h"
44
51static int print_bind(enum MenuType menu, FILE *fp)
52{
53 struct BindingInfoArray bia_bind = ARRAY_HEAD_INITIALIZER;
54
55 gather_menu(menu, &bia_bind, NULL);
56 if (ARRAY_EMPTY(&bia_bind))
57 return 0;
58
59 ARRAY_SORT(&bia_bind, binding_sort, NULL);
60 const int wb0 = measure_column(&bia_bind, 0);
61 const int wb1 = measure_column(&bia_bind, 1);
62
63 const char *menu_name = mutt_map_get_name(menu, MenuNames);
64
65 struct BindingInfo *bi = NULL;
66 ARRAY_FOREACH(bi, &bia_bind)
67 {
68 //XXX use description?
69 fprintf(fp, "bind %s %*s %*s # %s\n", menu_name, -wb0, bi->a[0], -wb1,
70 bi->a[1], bi->a[2]);
71 }
72
73 const int count = ARRAY_SIZE(&bia_bind);
74 ARRAY_FOREACH(bi, &bia_bind)
75 {
76 // we only need to free the keybinding
77 FREE(&bi->a[0]);
78 }
79
80 return count;
81}
82
88static void colon_bind(enum MenuType menu, FILE *fp)
89{
90 if (menu == MENU_MAX)
91 {
92 for (enum MenuType i = 1; i < MENU_MAX; i++)
93 {
94 if (print_bind(i, fp) > 0)
95 fprintf(fp, "\n");
96 }
97 }
98 else
99 {
100 print_bind(menu, fp);
101 }
102}
103
110static int print_macro(enum MenuType menu, FILE *fp)
111{
112 struct BindingInfoArray bia_macro = ARRAY_HEAD_INITIALIZER;
113
114 gather_menu(menu, NULL, &bia_macro);
115 if (ARRAY_EMPTY(&bia_macro))
116 return 0;
117
118 ARRAY_SORT(&bia_macro, binding_sort, NULL);
119 const int wm0 = measure_column(&bia_macro, 0);
120
121 const char *menu_name = mutt_map_get_name(menu, MenuNames);
122
123 struct BindingInfo *bi = NULL;
124 ARRAY_FOREACH(bi, &bia_macro)
125 {
126 if (bi->a[2]) // description
127 {
128 fprintf(fp, "macro %s %*s \"%s\" \"%s\"\n", menu_name, -wm0, bi->a[0],
129 bi->a[1], bi->a[2]);
130 }
131 else
132 {
133 fprintf(fp, "macro %s %*s \"%s\"\n", menu_name, -wm0, bi->a[0], bi->a[1]);
134 }
135 }
136
137 const int count = ARRAY_SIZE(&bia_macro);
138 ARRAY_FOREACH(bi, &bia_macro)
139 {
140 // free the keybinding and the macro text
141 FREE(&bi->a[0]);
142 FREE(&bi->a[1]);
143 }
144
145 ARRAY_FREE(&bia_macro);
146 return count;
147}
148
154static void colon_macro(enum MenuType menu, FILE *fp)
155{
156 if (menu == MENU_MAX)
157 {
158 for (enum MenuType i = 1; i < MENU_MAX; i++)
159 {
160 if (print_macro(i, fp) > 0)
161 {
162 //XXX need to elide last blank line
163 fprintf(fp, "\n");
164 }
165 }
166 }
167 else
168 {
169 print_macro(menu, fp);
170 }
171}
172
176enum CommandResult dump_bind_macro(struct Buffer *buf, struct Buffer *s,
177 intptr_t data, struct Buffer *err)
178{
179 FILE *fp = NULL;
180 struct Buffer *tempfile = NULL;
181 bool dump_all = false;
182 bool bind = (data == 0);
183 int rc = MUTT_CMD_ERROR;
184
185 if (!MoreArgs(s))
186 dump_all = true;
187 else
189
190 if (MoreArgs(s))
191 {
192 /* More arguments potentially means the user is using the
193 * ::command_t :bind command thus we delegate the task. */
194 goto done;
195 }
196
197 tempfile = buf_pool_get();
198 buf_mktemp(tempfile);
199 fp = mutt_file_fopen(buf_string(tempfile), "w");
200 if (!fp)
201 {
202 // L10N: '%s' is the file name of the temporary file
203 buf_printf(err, _("Could not create temporary file %s"), buf_string(tempfile));
204 goto done;
205 }
206
207 if (dump_all || mutt_istr_equal(buf_string(buf), "all"))
208 {
209 if (bind)
210 colon_bind(MENU_MAX, fp);
211 else
213 }
214 else
215 {
216 const int menu = mutt_map_get_value(buf_string(buf), MenuNames);
217 if (menu == -1)
218 {
219 // L10N: '%s' is the (misspelled) name of the menu, e.g. 'index' or 'pager'
220 buf_printf(err, _("%s: no such menu"), buf_string(buf));
221 goto done;
222 }
223
224 if (bind)
225 colon_bind(menu, fp);
226 else
227 colon_macro(menu, fp);
228 }
229
230 if (ftello(fp) == 0)
231 {
232 // L10N: '%s' is the name of the menu, e.g. 'index' or 'pager',
233 // it might also be 'all' when all menus are affected.
234 buf_printf(err, bind ? _("%s: no binds for this menu") : _("%s: no macros for this menu"),
235 dump_all ? "all" : buf_string(buf));
236 goto done;
237 }
238 mutt_file_fclose(&fp);
239
240 struct PagerData pdata = { 0 };
241 struct PagerView pview = { &pdata };
242
243 pdata.fname = buf_string(tempfile);
244
245 pview.banner = bind ? "bind" : "macro";
247 pview.mode = PAGER_MODE_OTHER;
248
249 mutt_do_pager(&pview, NULL);
250 rc = MUTT_CMD_SUCCESS;
251
252done:
253 mutt_file_fclose(&fp);
254 buf_pool_release(&tempfile);
255
256 return rc;
257}
258
262int binding_sort(const void *a, const void *b, void *sdata)
263{
264 const struct BindingInfo *x = (const struct BindingInfo *) a;
265 const struct BindingInfo *y = (const struct BindingInfo *) b;
266
267 int rc = mutt_str_cmp(x->a[0], y->a[0]);
268 if (rc != 0)
269 return rc;
270
271 // No binding, sort by function instead
272 return mutt_str_cmp(x->a[1], y->a[1]);
273}
274
282void escape_macro(const char *macro, struct Buffer *buf)
283{
284 wchar_t wc = 0;
285 size_t k;
286 size_t len = mutt_str_len(macro);
287 mbstate_t mbstate1 = { 0 };
288 mbstate_t mbstate2 = { 0 };
289
290 for (; (len > 0) && (k = mbrtowc(&wc, macro, MB_LEN_MAX, &mbstate1)); macro += k, len -= k)
291 {
292 if ((k == ICONV_ILLEGAL_SEQ) || (k == ICONV_BUF_TOO_SMALL))
293 {
294 if (k == ICONV_ILLEGAL_SEQ)
295 memset(&mbstate1, 0, sizeof(mbstate1));
296 k = (k == ICONV_ILLEGAL_SEQ) ? 1 : len;
297 wc = ReplacementChar;
298 }
299
300 const int w = wcwidth(wc);
301 if (IsWPrint(wc) && (w >= 0))
302 {
303 char tmp[MB_LEN_MAX * 2] = { 0 };
304 if (wcrtomb(tmp, wc, &mbstate2) != ICONV_ILLEGAL_SEQ)
305 {
306 buf_addstr(buf, tmp);
307 }
308 }
309 else if ((wc < 0x20) || (wc == 0x7f))
310 {
311 if (wc == '\033') // Escape
312 buf_addstr(buf, "\\e");
313 else if (wc == '\n')
314 buf_addstr(buf, "\\n");
315 else if (wc == '\r')
316 buf_addstr(buf, "\\r");
317 else if (wc == '\t')
318 buf_addstr(buf, "\\t");
319 else
320 buf_add_printf(buf, "^%c", (char) ((wc + '@') & 0x7f));
321 }
322 else
323 {
324 buf_addch(buf, '?');
325 }
326 }
327}
328
336static const char *help_lookup_function(int op, enum MenuType menu)
337{
338 if ((menu != MENU_PAGER) && (menu != MENU_EDITOR) && (menu != MENU_GENERIC))
339 {
340 /* first look in the generic map for the function */
341 const char *fn_name = mutt_get_func(OpGeneric, op);
342 if (fn_name)
343 return fn_name;
344 }
345
346 const struct MenuFuncOp *funcs = km_get_table(menu);
347
348 return mutt_get_func(funcs, op);
349}
350
357void gather_menu(enum MenuType menu, struct BindingInfoArray *bia_bind,
358 struct BindingInfoArray *bia_macro)
359{
360 struct Buffer *key_binding = buf_pool_get();
361 struct Buffer *macro = buf_pool_get();
362
363 struct Keymap *map = NULL;
364 STAILQ_FOREACH(map, &Keymaps[menu], entries)
365 {
366 struct BindingInfo bi = { 0 };
367
368 buf_reset(key_binding);
369 km_expand_key(map, key_binding);
370
371 if (map->op == OP_MACRO)
372 {
373 if (!bia_macro || (map->op == OP_NULL))
374 continue;
375
376 buf_reset(macro);
377 escape_macro(map->macro, macro);
378 bi.a[0] = buf_strdup(key_binding);
379 bi.a[1] = buf_strdup(macro);
380 bi.a[2] = map->desc;
381 ARRAY_ADD(bia_macro, bi);
382 }
383 else
384 {
385 if (!bia_bind)
386 continue;
387
388 if (map->op == OP_NULL)
389 {
390 bi.a[0] = buf_strdup(key_binding);
391 bi.a[1] = "noop";
392 ARRAY_ADD(bia_bind, bi);
393 continue;
394 }
395
396 bi.a[0] = buf_strdup(key_binding);
397 bi.a[1] = help_lookup_function(map->op, menu);
398 bi.a[2] = _(opcodes_get_description(map->op));
399 ARRAY_ADD(bia_bind, bi);
400 }
401 }
402
403 buf_pool_release(&key_binding);
404 buf_pool_release(&macro);
405}
406
413int measure_column(struct BindingInfoArray *bia, int col)
414{
415 int max_width = 0;
416
417 struct BindingInfo *bi = NULL;
418 ARRAY_FOREACH(bi, bia)
419 {
420 const int col_width = mutt_strwidth(bi->a[col]);
421 max_width = MAX(max_width, col_width);
422 }
423
424 return max_width;
425}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition array.h:335
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:156
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:214
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
CommandResult
Error codes for command_t parse functions.
Definition command.h:35
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition command.h:38
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:36
Convenience wrapper for the core headers.
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition curs_lib.c:445
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition do_pager.c:122
int parse_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition extract.c:48
#define MoreArgs(buf)
Definition extract.h:30
#define TOKEN_NO_FLAGS
No flags are set.
Definition extract.h:44
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
enum CommandResult dump_bind_macro(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse 'bind' and 'macro' commands - Implements Command::parse() -.
Definition dump.c:176
int binding_sort(const void *a, const void *b, void *sdata)
Compare two BindingInfo by their keybinding - Implements sort_t -.
Definition dump.c:262
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition functions.c:69
Convenience wrapper for the gui headers.
static void colon_macro(enum MenuType menu, FILE *fp)
Dump the macros.
Definition dump.c:154
int measure_column(struct BindingInfoArray *bia, int col)
Measure one column of a table.
Definition dump.c:413
static const char * help_lookup_function(int op, enum MenuType menu)
Find a keybinding for an operation.
Definition dump.c:336
void gather_menu(enum MenuType menu, struct BindingInfoArray *bia_bind, struct BindingInfoArray *bia_macro)
Gather info about one menu.
Definition dump.c:357
static void colon_bind(enum MenuType menu, FILE *fp)
Dump the key bindings.
Definition dump.c:88
static int print_bind(enum MenuType menu, FILE *fp)
Display the bindings for one menu.
Definition dump.c:51
static int print_macro(enum MenuType menu, FILE *fp)
Display the macros for one menu.
Definition dump.c:110
void escape_macro(const char *macro, struct Buffer *buf)
Escape any special characters in a macro.
Definition dump.c:282
struct KeymapList Keymaps[MENU_MAX]
Array of key mappings, one for each MenuType.
Definition lib.c:125
const char * mutt_get_func(const struct MenuFuncOp *funcs, int op)
Get the name of a function.
Definition lib.c:321
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition lib.c:482
bool km_expand_key(struct Keymap *map, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition lib.c:434
Manage keymappings.
int mutt_map_get_value(const char *name, const struct Mapping *map)
Lookup the constant for a string.
Definition mapping.c:85
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition mapping.c:42
#define IsWPrint(wc)
Definition mbyte.h:41
#define FREE(x)
Definition memory.h:62
#define MAX(a, b)
Definition memory.h:36
GUI present the user with a selectable list.
wchar_t ReplacementChar
When a Unicode character can't be displayed, use this instead.
Definition charset.c:61
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition charset.h:98
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition charset.h:96
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
int mutt_str_cmp(const char *a, const char *b)
Compare two strings, safely.
Definition string.c:401
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:672
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
const char * opcodes_get_description(int op)
Get the description of an opcode.
Definition opcodes.c:68
GUI display a file/email/help in a viewport with paging.
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition lib.h:60
@ PAGER_MODE_OTHER
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition lib.h:140
Text parsing functions.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
Info about one keybinding.
Definition lib.h:95
const char * a[3]
Array of info.
Definition lib.h:96
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
A keyboard mapping.
Definition lib.h:67
char * macro
Macro expansion (op == OP_MACRO)
Definition lib.h:68
char * desc
Description of a macro for the help menu.
Definition lib.h:69
short op
Operation to perform.
Definition lib.h:70
Mapping between a function and an operation.
Definition lib.h:115
int op
Operation, e.g. OP_DELETE.
Definition lib.h:117
Data to be displayed by PagerView.
Definition lib.h:159
const char * fname
Name of the file to read.
Definition lib.h:163
Paged view into some data.
Definition lib.h:170
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition lib.h:171
enum PagerMode mode
Pager mode.
Definition lib.h:172
PagerFlags flags
Additional settings to tweak pager's function.
Definition lib.h:173
const char * banner
Title to display in status bar.
Definition lib.h:174
#define buf_mktemp(buf)
Definition tmp.h:33
const struct Mapping MenuNames[]
Menu name lookup table.
Definition type.c:37
MenuType
Types of GUI selections.
Definition type.h:35
@ MENU_GENERIC
Generic selection list.
Definition type.h:45
@ MENU_PAGER
Pager pager (email viewer)
Definition type.h:47
@ MENU_MAX
Definition type.h:52
@ MENU_EDITOR
Text entry area.
Definition type.h:44