NeoMutt  2020-06-26-30-g76c339
Teaching an old dog new tricks
DOXYGEN
curs_lib.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <stddef.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <langinfo.h>
36 #include <limits.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <termios.h>
42 #include <unistd.h>
43 #include <wchar.h>
44 #include "mutt/lib.h"
45 #include "config/lib.h"
46 #include "core/lib.h"
47 #include "mutt.h"
48 #include "curs_lib.h"
49 #include "browser.h"
50 #include "color.h"
51 #include "enter_state.h"
52 #include "globals.h"
53 #include "keymap.h"
54 #include "mutt_curses.h"
55 #include "mutt_logging.h"
56 #include "mutt_menu.h"
57 #include "mutt_window.h"
58 #include "opcodes.h"
59 #include "options.h"
60 #include "pager.h"
61 #include "protos.h"
62 #ifdef HAVE_ISWBLANK
63 #include <wctype.h>
64 #endif
65 #ifdef USE_INOTIFY
66 #include "monitor.h"
67 #endif
68 
69 /* These Config Variables are only used in curs_lib.c */
70 bool C_MetaKey;
71 
72 /* not possible to unget more than one char under some curses libs, and it
73  * is impossible to unget function keys in SLang, so roll our own input
74  * buffering routines.
75  */
76 
77 /* These are used for macros and exec/push commands.
78  * They can be temporarily ignored by setting OptIgnoreMacroEvents
79  */
80 static size_t MacroBufferCount = 0;
81 static size_t MacroBufferLen = 0;
82 static struct KeyEvent *MacroEvents;
83 
84 /* These are used in all other "normal" situations, and are not
85  * ignored when setting OptIgnoreMacroEvents
86  */
87 static size_t UngetCount = 0;
88 static size_t UngetLen = 0;
89 static struct KeyEvent *UngetKeyEvents;
90 
92 
97 void mutt_beep(bool force)
98 {
99  if (force || C_Beep)
100  beep();
101 }
102 
106 void mutt_refresh(void)
107 {
108  /* don't refresh when we are waiting for a child. */
109  if (OptKeepQuiet)
110  return;
111 
112  /* don't refresh in the middle of macros unless necessary */
114  return;
115 
116  /* else */
117  refresh();
118 }
119 
129 {
130  keypad(stdscr, true);
131  clearok(stdscr, true);
133 }
134 
144 void mutt_getch_timeout(int delay)
145 {
146  MuttGetchTimeout = delay;
147  timeout(delay);
148 }
149 
150 #ifdef USE_INOTIFY
151 
156 static int mutt_monitor_getch(void)
157 {
158  /* ncurses has its own internal buffer, so before we perform a poll,
159  * we need to make sure there isn't a character waiting */
160  timeout(0);
161  int ch = getch();
162  timeout(MuttGetchTimeout);
163  if (ch == ERR)
164  {
165  if (mutt_monitor_poll() != 0)
166  ch = ERR;
167  else
168  ch = getch();
169  }
170  return ch;
171 }
172 #endif /* USE_INOTIFY */
173 
187 struct KeyEvent mutt_getch(void)
188 {
189  int ch;
190  struct KeyEvent err = { -1, OP_NULL }, ret;
191  struct KeyEvent timeout = { -2, OP_NULL };
192 
193  if (UngetCount)
194  return UngetKeyEvents[--UngetCount];
195 
197  return MacroEvents[--MacroBufferCount];
198 
199  SigInt = 0;
200 
202 #ifdef KEY_RESIZE
203  /* ncurses 4.2 sends this when the screen is resized */
204  ch = KEY_RESIZE;
205  while (ch == KEY_RESIZE)
206 #endif /* KEY_RESIZE */
207 #ifdef USE_INOTIFY
208  ch = mutt_monitor_getch();
209 #else
210  ch = getch();
211 #endif /* USE_INOTIFY */
213 
214  if (SigInt)
215  {
216  mutt_query_exit();
217  return err;
218  }
219 
220  /* either timeout, a sigwinch (if timeout is set), or the terminal
221  * has been lost */
222  if (ch == ERR)
223  {
224  if (!isatty(0))
225  mutt_exit(1);
226 
227  return timeout;
228  }
229 
230  if ((ch & 0x80) && C_MetaKey)
231  {
232  /* send ALT-x as ESC-x */
233  ch &= ~0x80;
234  mutt_unget_event(ch, 0);
235  ret.ch = '\033'; // Escape
236  ret.op = 0;
237  return ret;
238  }
239 
240  ret.ch = ch;
241  ret.op = 0;
242  return (ch == AbortKey) ? err : ret;
243 }
244 
257 int mutt_buffer_get_field_full(const char *field, struct Buffer *buf, CompletionFlags complete,
258  bool multiple, char ***files, int *numfiles)
259 {
260  int ret;
261  int col;
262 
263  struct EnterState *es = mutt_enter_state_new();
264 
265  do
266  {
267  if (SigWinch)
268  {
269  SigWinch = 0;
271  clearok(stdscr, true);
273  }
276  mutt_window_addstr(field);
278  mutt_refresh();
280  ret = mutt_enter_string_full(buf->data, buf->dsize, col, complete, multiple,
281  files, numfiles, es);
282  } while (ret == 1);
283 
284  if (ret == 0)
286  else
287  mutt_buffer_reset(buf);
288 
291 
292  return ret;
293 }
294 
308 int mutt_get_field_full(const char *field, char *buf, size_t buflen, CompletionFlags complete,
309  bool multiple, char ***files, int *numfiles)
310 {
311  if (!buf)
312  return -1;
313 
314  struct Buffer tmp = {
315  .data = buf,
316  .dptr = buf + mutt_str_len(buf),
317  .dsize = buflen,
318  };
319  return mutt_buffer_get_field_full(field, &tmp, complete, multiple, files, numfiles);
320 }
321 
332 int mutt_get_field_unbuffered(const char *msg, char *buf, size_t buflen, CompletionFlags flags)
333 {
334  bool reset_ignoremacro = false;
335 
337  {
338  OptIgnoreMacroEvents = true;
339  reset_ignoremacro = true;
340  }
341  int rc = mutt_get_field(msg, buf, buflen, flags);
342  if (reset_ignoremacro)
343  OptIgnoreMacroEvents = false;
344 
345  return rc;
346 }
347 
353 void mutt_edit_file(const char *editor, const char *file)
354 {
355  struct Buffer *cmd = mutt_buffer_pool_get();
356 
357  mutt_endwin();
358  mutt_buffer_file_expand_fmt_quote(cmd, editor, file);
359  if (mutt_system(mutt_b2s(cmd)) != 0)
360  {
361  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
362  }
363  /* the terminal may have been resized while the editor owned it */
365  keypad(stdscr, true);
366  clearok(stdscr, true);
367 
369 }
370 
377 enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
378 {
379  struct KeyEvent ch;
380  char *yes = _("yes");
381  char *no = _("no");
382  char *answer_string = NULL;
383  int answer_string_wid, msg_wid;
384  size_t trunc_msg_len;
385  bool redraw = true;
386  int prompt_lines = 1;
387 
388  char *expr = NULL;
389  regex_t reyes;
390  regex_t reno;
391  char answer[2];
392 
393  answer[1] = '\0';
394 
395  bool reyes_ok = (expr = nl_langinfo(YESEXPR)) && (expr[0] == '^') &&
396  (REG_COMP(&reyes, expr, REG_NOSUB) == 0);
397  bool reno_ok = (expr = nl_langinfo(NOEXPR)) && (expr[0] == '^') &&
398  (REG_COMP(&reno, expr, REG_NOSUB) == 0);
399 
400  /* In order to prevent the default answer to the question to wrapped
401  * around the screen in the even the question is wider than the screen,
402  * ensure there is enough room for the answer and truncate the question
403  * to fit. */
404  mutt_str_asprintf(&answer_string, " ([%s]/%s): ", (def == MUTT_YES) ? yes : no,
405  (def == MUTT_YES) ? no : yes);
406  answer_string_wid = mutt_strwidth(answer_string);
407  msg_wid = mutt_strwidth(msg);
408 
409  while (true)
410  {
411  if (redraw || SigWinch)
412  {
413  redraw = false;
414  if (SigWinch)
415  {
416  SigWinch = 0;
418  clearok(stdscr, true);
420  }
422  {
423  prompt_lines = (msg_wid + answer_string_wid + MuttMessageWindow->state.cols - 1) /
425  prompt_lines = MAX(1, MIN(3, prompt_lines));
426  }
427  if (prompt_lines != MuttMessageWindow->state.rows)
428  {
429  mutt_window_reflow_message_rows(prompt_lines);
431  }
432 
433  /* maxlen here is sort of arbitrary, so pick a reasonable upper bound */
434  trunc_msg_len = mutt_wstr_trunc(
435  msg, (size_t) 4 * prompt_lines * MuttMessageWindow->state.cols,
436  ((size_t) prompt_lines * MuttMessageWindow->state.cols) - answer_string_wid, NULL);
437 
440  mutt_window_addnstr(msg, trunc_msg_len);
441  mutt_window_addstr(answer_string);
444  }
445 
446  mutt_refresh();
447  /* SigWinch is not processed unless timeout is set */
448  mutt_getch_timeout(30 * 1000);
449  ch = mutt_getch();
450  mutt_getch_timeout(-1);
451  if (ch.ch == -2)
452  continue;
453  if (CI_is_return(ch.ch))
454  break;
455  if (ch.ch < 0)
456  {
457  def = MUTT_ABORT;
458  break;
459  }
460 
461  answer[0] = ch.ch;
462  if (reyes_ok ? (regexec(&reyes, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'y'))
463  {
464  def = MUTT_YES;
465  break;
466  }
467  else if (reno_ok ? (regexec(&reno, answer, 0, 0, 0) == 0) : (tolower(ch.ch) == 'n'))
468  {
469  def = MUTT_NO;
470  break;
471  }
472  else
473  {
474  mutt_beep(false);
475  }
476  }
477 
478  FREE(&answer_string);
479 
480  if (reyes_ok)
481  regfree(&reyes);
482  if (reno_ok)
483  regfree(&reno);
484 
485  if (MuttMessageWindow->state.rows == 1)
486  {
488  }
489  else
490  {
493  }
494 
495  if (def == MUTT_ABORT)
496  {
497  /* when the users cancels with ^G, clear the message stored with
498  * mutt_message() so it isn't displayed when the screen is refreshed. */
500  }
501  else
502  {
503  mutt_window_addstr((char *) ((def == MUTT_YES) ? yes : no));
504  mutt_refresh();
505  }
506  return def;
507 }
508 
514 void mutt_query_exit(void)
515 {
516  mutt_flushinp();
518  if (C_Timeout)
519  mutt_getch_timeout(-1); /* restore blocking operation */
520  if (mutt_yesorno(_("Exit NeoMutt?"), MUTT_YES) == MUTT_YES)
521  {
522  mutt_exit(1);
523  }
526  SigInt = 0;
527 }
528 
532 void mutt_show_error(void)
533 {
535  return;
536 
541 }
542 
546 void mutt_endwin(void)
547 {
548  if (OptNoCurses)
549  return;
550 
551  int e = errno;
552 
553  /* at least in some situations (screen + xterm under SuSE11/12) endwin()
554  * doesn't properly flush the screen without an explicit call. */
555  mutt_refresh();
556  endwin();
557 
558  errno = e;
559 }
560 
565 void mutt_perror_debug(const char *s)
566 {
567  char *p = strerror(errno);
568 
569  mutt_debug(LL_DEBUG1, "%s: %s (errno = %d)\n", s, p ? p : "unknown error", errno);
570  mutt_error("%s: %s (errno = %d)", s, p ? p : _("unknown error"), errno);
571 }
572 
579 int mutt_any_key_to_continue(const char *s)
580 {
581  struct termios term;
582  struct termios old;
583 
584  int fd = open("/dev/tty", O_RDONLY);
585  if (fd < 0)
586  return EOF;
587 
588  tcgetattr(fd, &old); // Save the current tty settings
589 
590  term = old;
591  term.c_lflag &= ~(ICANON | ECHO); // Canonical (not line-buffered), don't echo the characters
592  term.c_cc[VMIN] = 1; // Wait for at least one character
593  term.c_cc[VTIME] = 255; // Wait for 25.5s
594  tcsetattr(fd, TCSANOW, &term);
595 
596  if (s)
597  fputs(s, stdout);
598  else
599  fputs(_("Press any key to continue..."), stdout);
600  fflush(stdout);
601 
602  char ch = '\0';
603  // Wait for a character. This might timeout, so loop.
604  while (read(fd, &ch, 1) == 0)
605  ; // do nothing
606 
607  // Change the tty settings to be non-blocking
608  term.c_cc[VMIN] = 0; // Returning with zero characters is acceptable
609  term.c_cc[VTIME] = 0; // Don't wait
610  tcsetattr(fd, TCSANOW, &term);
611 
612  char buf[64];
613  while (read(fd, buf, sizeof(buf)) > 0)
614  ; // Mop up any remaining chars
615 
616  tcsetattr(fd, TCSANOW, &old); // Restore the previous tty settings
617  close(fd);
618 
619  fputs("\r\n", stdout);
621  return (ch >= 0) ? ch : EOF;
622 }
623 
628 {
629  if (!nc->event_data || !nc->global_data)
630  return -1;
631  if (nc->event_type != NT_CONFIG)
632  return 0;
633 
634  struct EventConfig *ec = nc->event_data;
635  struct MuttWindow *dlg = nc->global_data;
636 
637  if (!mutt_str_equal(ec->name, "status_on_top"))
638  return 0;
639 
640  struct MuttWindow *win_first = TAILQ_FIRST(&dlg->children);
641  if (!win_first)
642  return -1;
643 
644  if ((C_StatusOnTop && (win_first->type == WT_PAGER)) ||
645  (!C_StatusOnTop && (win_first->type != WT_PAGER)))
646  {
647  // Swap the Index and the IndexBar Windows
648  TAILQ_REMOVE(&dlg->children, win_first, entries);
649  TAILQ_INSERT_TAIL(&dlg->children, win_first, entries);
650  }
651 
652  mutt_window_reflow(dlg);
653  return 0;
654 }
655 
665 int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color,
666  struct Pager *info)
667 {
668  struct Pager info2 = { 0 };
669  if (!info)
670  info = &info2;
671 
672  struct MuttWindow *dlg =
675  dlg->notify = notify_new();
676 
677  struct MuttWindow *pager =
680  pager->notify = notify_new();
681  notify_set_parent(pager->notify, dlg->notify);
682 
683  struct MuttWindow *pbar =
686  pbar->notify = notify_new();
687  notify_set_parent(pbar->notify, dlg->notify);
688 
689  if (C_StatusOnTop)
690  {
691  mutt_window_add_child(dlg, pbar);
692  mutt_window_add_child(dlg, pager);
693  }
694  else
695  {
696  mutt_window_add_child(dlg, pager);
697  mutt_window_add_child(dlg, pbar);
698  }
699 
701  dialog_push(dlg);
702 
703  info->win_ibar = NULL;
704  info->win_index = NULL;
705  info->win_pbar = pbar;
706  info->win_pager = pager;
707 
708  int rc;
709 
710  if (!C_Pager || mutt_str_equal(C_Pager, "builtin"))
711  rc = mutt_pager(banner, tempfile, do_color, info);
712  else
713  {
714  struct Buffer *cmd = mutt_buffer_pool_get();
715 
716  mutt_endwin();
718  if (mutt_system(mutt_b2s(cmd)) == -1)
719  {
720  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
721  rc = -1;
722  }
723  else
724  rc = 0;
725  mutt_file_unlink(tempfile);
727  }
728 
729  dialog_pop();
731  mutt_window_free(&dlg);
732  return rc;
733 }
734 
747 int mutt_buffer_enter_fname_full(const char *prompt, struct Buffer *fname,
748  bool mailbox, bool multiple, char ***files,
749  int *numfiles, SelectFileFlags flags)
750 {
751  struct KeyEvent ch;
752 
755  mutt_window_addstr(_(" ('?' for list): "));
757  if (!mutt_buffer_is_empty(fname))
760  mutt_refresh();
761 
762  do
763  {
764  ch = mutt_getch();
765  } while (ch.ch == -2);
766  if (ch.ch < 0)
767  {
769  return -1;
770  }
771  else if (ch.ch == '?')
772  {
773  mutt_refresh();
774  mutt_buffer_reset(fname);
775 
776  if (flags == MUTT_SEL_NO_FLAGS)
777  flags = MUTT_SEL_FOLDER;
778  if (multiple)
779  flags |= MUTT_SEL_MULTI;
780  if (mailbox)
781  flags |= MUTT_SEL_MAILBOX;
782  mutt_buffer_select_file(fname, flags, files, numfiles);
783  }
784  else
785  {
786  char *pc = mutt_mem_malloc(mutt_str_len(prompt) + 3);
787 
788  sprintf(pc, "%s: ", prompt);
789  if (ch.op == OP_NULL)
790  mutt_unget_event(ch.ch, 0);
791  else
792  mutt_unget_event(0, ch.op);
793 
794  mutt_buffer_alloc(fname, 1024);
795  if (mutt_buffer_get_field_full(pc, fname, (mailbox ? MUTT_EFILE : MUTT_FILE) | MUTT_CLEAR,
796  multiple, files, numfiles) != 0)
797  {
798  mutt_buffer_reset(fname);
799  }
800  FREE(&pc);
801  }
802 
803  return 0;
804 }
805 
813 void mutt_unget_event(int ch, int op)
814 {
815  struct KeyEvent tmp;
816 
817  tmp.ch = ch;
818  tmp.op = op;
819 
820  if (UngetCount >= UngetLen)
821  mutt_mem_realloc(&UngetKeyEvents, (UngetLen += 16) * sizeof(struct KeyEvent));
822 
823  UngetKeyEvents[UngetCount++] = tmp;
824 }
825 
832 void mutt_unget_string(const char *s)
833 {
834  const char *p = s + mutt_str_len(s) - 1;
835 
836  while (p >= s)
837  {
838  mutt_unget_event((unsigned char) *p--, 0);
839  }
840 }
841 
851 {
852  struct KeyEvent tmp;
853 
854  tmp.ch = ch;
855  tmp.op = op;
856 
858  mutt_mem_realloc(&MacroEvents, (MacroBufferLen += 128) * sizeof(struct KeyEvent));
859 
860  MacroEvents[MacroBufferCount++] = tmp;
861 }
862 
870 {
871  UngetCount = 0;
872  while (MacroBufferCount > 0)
873  {
874  if (MacroEvents[--MacroBufferCount].op == OP_END_COND)
875  return;
876  }
877 }
878 
887 {
888  while (UngetCount > 0)
889  {
890  if (UngetKeyEvents[--UngetCount].op == OP_END_COND)
891  return;
892  }
893 }
894 
898 void mutt_flushinp(void)
899 {
900  UngetCount = 0;
901  MacroBufferCount = 0;
902  flushinp();
903 }
904 
912 int mutt_multi_choice(const char *prompt, const char *letters)
913 {
914  struct KeyEvent ch;
915  int choice;
916  bool redraw = true;
917  int prompt_lines = 1;
918 
919  bool opt_cols = ((Colors->defs[MT_COLOR_OPTIONS] != 0) &&
921 
922  while (true)
923  {
924  if (redraw || SigWinch)
925  {
926  redraw = false;
927  if (SigWinch)
928  {
929  SigWinch = 0;
931  clearok(stdscr, true);
933  }
935  {
936  int width = mutt_strwidth(prompt) + 2; // + '?' + space
937  /* If we're going to colour the options,
938  * make an assumption about the modified prompt size. */
939  if (opt_cols)
940  width -= 2 * mutt_str_len(letters);
941 
942  prompt_lines = (width + MuttMessageWindow->state.cols - 1) /
944  prompt_lines = MAX(1, MIN(3, prompt_lines));
945  }
946  if (prompt_lines != MuttMessageWindow->state.rows)
947  {
948  mutt_window_reflow_message_rows(prompt_lines);
950  }
951 
953 
954  if ((Colors->defs[MT_COLOR_OPTIONS] != 0) &&
956  {
957  char *cur = NULL;
958 
959  while ((cur = strchr(prompt, '(')))
960  {
961  // write the part between prompt and cur using MT_COLOR_PROMPT
963  mutt_window_addnstr(prompt, cur - prompt);
964 
965  if (isalnum(cur[1]) && (cur[2] == ')'))
966  {
967  // we have a single letter within parentheses
969  mutt_window_addch(cur[1]);
970  prompt = cur + 3;
971  }
972  else
973  {
974  // we have a parenthesis followed by something else
975  mutt_window_addch(cur[0]);
976  prompt = cur + 1;
977  }
978  }
979  }
980 
982  mutt_window_addstr(prompt);
984 
985  mutt_window_addch(' ');
987  }
988 
989  mutt_refresh();
990  /* SigWinch is not processed unless timeout is set */
991  mutt_getch_timeout(30 * 1000);
992  ch = mutt_getch();
993  mutt_getch_timeout(-1);
994  if (ch.ch == -2)
995  continue;
996  /* (ch.ch == 0) is technically possible. Treat the same as < 0 (abort) */
997  if ((ch.ch <= 0) || CI_is_return(ch.ch))
998  {
999  choice = -1;
1000  break;
1001  }
1002  else
1003  {
1004  char *p = strchr(letters, ch.ch);
1005  if (p)
1006  {
1007  choice = p - letters + 1;
1008  break;
1009  }
1010  else if ((ch.ch <= '9') && (ch.ch > '0'))
1011  {
1012  choice = ch.ch - '0';
1013  if (choice <= mutt_str_len(letters))
1014  break;
1015  }
1016  }
1017  mutt_beep(false);
1018  }
1019  if (MuttMessageWindow->state.rows == 1)
1020  {
1022  }
1023  else
1024  {
1027  }
1028  mutt_refresh();
1029  return choice;
1030 }
1031 
1038 int mutt_addwch(wchar_t wc)
1039 {
1040  char buf[MB_LEN_MAX * 2];
1041  mbstate_t mbstate;
1042  size_t n1, n2;
1043 
1044  memset(&mbstate, 0, sizeof(mbstate));
1045  if (((n1 = wcrtomb(buf, wc, &mbstate)) == (size_t)(-1)) ||
1046  ((n2 = wcrtomb(buf + n1, 0, &mbstate)) == (size_t)(-1)))
1047  {
1048  return -1; /* ERR */
1049  }
1050  else
1051  {
1052  return mutt_window_addstr(buf);
1053  }
1054 }
1055 
1072 void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width,
1073  enum FormatJustify justify, char pad_char,
1074  const char *s, size_t n, bool arboreal)
1075 {
1076  wchar_t wc;
1077  int w;
1078  size_t k, k2;
1079  char scratch[MB_LEN_MAX];
1080  mbstate_t mbstate1, mbstate2;
1081  bool escaped = false;
1082 
1083  memset(&mbstate1, 0, sizeof(mbstate1));
1084  memset(&mbstate2, 0, sizeof(mbstate2));
1085  buflen--;
1086  char *p = buf;
1087  for (; n && (k = mbrtowc(&wc, s, n, &mbstate1)); s += k, n -= k)
1088  {
1089  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1090  {
1091  if ((k == (size_t)(-1)) && (errno == EILSEQ))
1092  memset(&mbstate1, 0, sizeof(mbstate1));
1093 
1094  k = (k == (size_t)(-1)) ? 1 : n;
1095  wc = ReplacementChar;
1096  }
1097  if (escaped)
1098  {
1099  escaped = false;
1100  w = 0;
1101  }
1102  else if (arboreal && (wc == MUTT_SPECIAL_INDEX))
1103  {
1104  escaped = true;
1105  w = 0;
1106  }
1107  else if (arboreal && (wc < MUTT_TREE_MAX))
1108  {
1109  w = 1; /* hack */
1110  }
1111  else
1112  {
1113 #ifdef HAVE_ISWBLANK
1114  if (iswblank(wc))
1115  wc = ' ';
1116  else
1117 #endif
1118  if (!IsWPrint(wc))
1119  wc = '?';
1120  w = wcwidth(wc);
1121  }
1122  if (w >= 0)
1123  {
1124  if ((w > max_width) || ((k2 = wcrtomb(scratch, wc, &mbstate2)) > buflen))
1125  continue;
1126  min_width -= w;
1127  max_width -= w;
1128  strncpy(p, scratch, k2);
1129  p += k2;
1130  buflen -= k2;
1131  }
1132  }
1133  w = ((int) buflen < min_width) ? buflen : min_width;
1134  if (w <= 0)
1135  *p = '\0';
1136  else if (justify == JUSTIFY_RIGHT) /* right justify */
1137  {
1138  p[w] = '\0';
1139  while (--p >= buf)
1140  p[w] = *p;
1141  while (--w >= 0)
1142  buf[w] = pad_char;
1143  }
1144  else if (justify == JUSTIFY_CENTER) /* center */
1145  {
1146  char *savedp = p;
1147  int half = (w + 1) / 2; /* half of cushion space */
1148 
1149  p[w] = '\0';
1150 
1151  /* move str to center of buffer */
1152  while (--p >= buf)
1153  p[half] = *p;
1154 
1155  /* fill rhs */
1156  p = savedp + half;
1157  while (--w >= half)
1158  *p++ = pad_char;
1159 
1160  /* fill lhs */
1161  while (half--)
1162  buf[half] = pad_char;
1163  }
1164  else /* left justify */
1165  {
1166  while (--w >= 0)
1167  *p++ = pad_char;
1168  *p = '\0';
1169  }
1170 }
1171 
1186 void mutt_format_s_x(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
1187 {
1188  enum FormatJustify justify = JUSTIFY_RIGHT;
1189  char *p = NULL;
1190  int min_width;
1191  int max_width = INT_MAX;
1192 
1193  if (*prec == '-')
1194  {
1195  prec++;
1196  justify = JUSTIFY_LEFT;
1197  }
1198  else if (*prec == '=')
1199  {
1200  prec++;
1201  justify = JUSTIFY_CENTER;
1202  }
1203  min_width = strtol(prec, &p, 10);
1204  if (*p == '.')
1205  {
1206  prec = p + 1;
1207  max_width = strtol(prec, &p, 10);
1208  if (p <= prec)
1209  max_width = INT_MAX;
1210  }
1211 
1212  mutt_simple_format(buf, buflen, min_width, max_width, justify, ' ', s,
1213  mutt_str_len(s), arboreal);
1214 }
1215 
1223 void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
1224 {
1225  mutt_format_s_x(buf, buflen, prec, s, false);
1226 }
1227 
1235 void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
1236 {
1237  mutt_format_s_x(buf, buflen, prec, s, true);
1238 }
1239 
1245 void mutt_paddstr(int n, const char *s)
1246 {
1247  wchar_t wc;
1248  size_t k;
1249  size_t len = mutt_str_len(s);
1250  mbstate_t mbstate;
1251 
1252  memset(&mbstate, 0, sizeof(mbstate));
1253  for (; len && (k = mbrtowc(&wc, s, len, &mbstate)); s += k, len -= k)
1254  {
1255  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1256  {
1257  if (k == (size_t)(-1))
1258  memset(&mbstate, 0, sizeof(mbstate));
1259  k = (k == (size_t)(-1)) ? 1 : len;
1260  wc = ReplacementChar;
1261  }
1262  if (!IsWPrint(wc))
1263  wc = '?';
1264  const int w = wcwidth(wc);
1265  if (w >= 0)
1266  {
1267  if (w > n)
1268  break;
1269  mutt_window_addnstr((char *) s, k);
1270  n -= w;
1271  }
1272  }
1273  while (n-- > 0)
1274  mutt_window_addch(' ');
1275 }
1276 
1288 size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
1289 {
1290  wchar_t wc;
1291  size_t n, w = 0, l = 0, cl;
1292  int cw;
1293  mbstate_t mbstate;
1294 
1295  if (!src)
1296  goto out;
1297 
1298  n = mutt_str_len(src);
1299 
1300  memset(&mbstate, 0, sizeof(mbstate));
1301  for (w = 0; n && (cl = mbrtowc(&wc, src, n, &mbstate)); src += cl, n -= cl)
1302  {
1303  if ((cl == (size_t)(-1)) || (cl == (size_t)(-2)))
1304  {
1305  if (cl == (size_t)(-1))
1306  memset(&mbstate, 0, sizeof(mbstate));
1307  cl = (cl == (size_t)(-1)) ? 1 : n;
1308  wc = ReplacementChar;
1309  }
1310  cw = wcwidth(wc);
1311  /* hack because MUTT_TREE symbols aren't turned into characters
1312  * until rendered by print_enriched_string() */
1313  if ((cw < 0) && (src[0] == MUTT_SPECIAL_INDEX))
1314  {
1315  cl = 2; /* skip the index coloring sequence */
1316  cw = 0;
1317  }
1318  else if ((cw < 0) && (cl == 1) && (src[0] != '\0') && (src[0] < MUTT_TREE_MAX))
1319  cw = 1;
1320  else if (cw < 0)
1321  cw = 0; /* unprintable wchar */
1322  if ((cl + l > maxlen) || (cw + w > maxwid))
1323  break;
1324  l += cl;
1325  w += cw;
1326  }
1327 out:
1328  if (width)
1329  *width = w;
1330  return l;
1331 }
1332 
1338 int mutt_strwidth(const char *s)
1339 {
1340  if (!s)
1341  return 0;
1342  return mutt_strnwidth(s, mutt_str_len(s));
1343 }
1344 
1351 int mutt_strnwidth(const char *s, size_t n)
1352 {
1353  if (!s)
1354  return 0;
1355 
1356  wchar_t wc;
1357  int w;
1358  size_t k;
1359  mbstate_t mbstate;
1360 
1361  memset(&mbstate, 0, sizeof(mbstate));
1362  for (w = 0; n && (k = mbrtowc(&wc, s, n, &mbstate)); s += k, n -= k)
1363  {
1364  if (*s == MUTT_SPECIAL_INDEX)
1365  {
1366  s += 2; /* skip the index coloring sequence */
1367  k = 0;
1368  continue;
1369  }
1370 
1371  if ((k == (size_t)(-1)) || (k == (size_t)(-2)))
1372  {
1373  if (k == (size_t)(-1))
1374  memset(&mbstate, 0, sizeof(mbstate));
1375  k = (k == (size_t)(-1)) ? 1 : n;
1376  wc = ReplacementChar;
1377  }
1378  if (!IsWPrint(wc))
1379  wc = '?';
1380  w += wcwidth(wc);
1381  }
1382  return w;
1383 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:879
void mutt_perror_debug(const char *s)
Show the user an &#39;errno&#39; message.
Definition: curs_lib.c:565
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:247
struct MuttWindow * win_index
Definition: pager.h:74
#define CI_is_return(ch)
Definition: mutt_curses.h:71
Manage keymappings.
Define wrapper functions around Curses/Slang.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
Left justify the text.
Definition: curs_lib.h:47
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
FormatJustify
Alignment for mutt_simple_format()
Definition: curs_lib.h:45
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define MIN(a, b)
Definition: memory.h:31
#define IsWPrint(wc)
Definition: mbyte.h:40
Data passed to a notification function.
Definition: observer.h:39
Window management.
GUI miscellaneous curses (window drawing) routines.
uint16_t CompletionFlags
Flags for mutt_enter_string_full(), e.g. MUTT_ALIAS.
Definition: mutt.h:55
Informational message.
Definition: color.h:75
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1186
static struct KeyEvent * MacroEvents
Definition: curs_lib.c:82
Pager Bar containing status info about the Pager.
Definition: mutt_window.h:97
User aborted the question (with Ctrl-G)
Definition: quad.h:38
Window uses all available vertical space.
Definition: mutt_window.h:35
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void mutt_push_macro_event(int ch, int op)
Add the character/operation to the macro buffer.
Definition: curs_lib.c:850
static size_t MacroBufferCount
Definition: curs_lib.c:80
WHERE SIG_ATOMIC_VOLATILE_T SigInt
true after SIGINT is received
Definition: globals.h:79
void mutt_curses_set_color(enum ColorId color)
Set the current colour for text.
Definition: mutt_curses.c:55
void dialog_pop(void)
Hide a Window from the user.
Definition: mutt_window.c:722
int * defs
Array of all fixed colours, see enum ColorId.
Definition: color.h:131
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: curs_lib.c:898
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:212
void mutt_resize_screen(void)
Update NeoMutt&#39;s opinion about the window size (CURSES)
Definition: resize.c:101
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: mutt_window.c:697
Right justify the text.
Definition: curs_lib.h:49
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
A config-change event.
Definition: subset.h:70
String manipulation buffer.
Definition: buffer.h:33
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:813
#define _(a)
Definition: message.h:28
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
int mutt_enter_string_full(char *buf, size_t buflen, int col, CompletionFlags flags, bool multiple, char ***files, int *numfiles, struct EnterState *state)
Ask the user for a string.
Definition: enter.c:177
int op
function op
Definition: keymap.h:64
int ch
raw key pressed
Definition: keymap.h:63
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: browser.h:44
WHERE bool OptIgnoreMacroEvents
(pseudo) don&#39;t process macro/push/exec events while set
Definition: options.h:38
A division of the screen.
Definition: mutt_window.h:108
void mutt_query_exit(void)
Ask the user if they want to leave NeoMutt.
Definition: curs_lib.c:514
An email being displayed.
Definition: pager.h:65
int mutt_window_mvaddstr(struct MuttWindow *win, int col, int row, const char *str)
Move the cursor and write a fixed string to a Window.
Definition: mutt_window.c:379
All user-callable functions.
Container for Accounts, Notifications.
Definition: neomutt.h:36
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:238
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:90
Convenience wrapper for the config headers.
void mutt_paddstr(int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:1245
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:365
GUI component for displaying/selecting items from a list.
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: browser.h:47
Hundreds of global variables to back the user variables.
wchar_t ReplacementChar
When a Unicode character can&#39;t be displayed, use this instead.
Definition: charset.c:58
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:150
static size_t UngetCount
Definition: curs_lib.c:87
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:97
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:41
#define MAX(a, b)
Definition: memory.h:30
size_t dsize
Length of data.
Definition: buffer.h:37
int mutt_window_addnstr(const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:503
void mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:76
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:377
struct Notify * notify
Notifications system.
Definition: mutt_window.h:123
Many unsorted constants and some structs.
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition: curs_lib.c:869
Centre the text.
Definition: curs_lib.h:48
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:190
Display a normal cursor.
Definition: mutt_curses.h:81
Convenience wrapper for the core headers.
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
WHERE SIG_ATOMIC_VOLATILE_T SigWinch
true after SIGWINCH is received
Definition: globals.h:80
Struct to store the cursor position when entering text.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
int mutt_monitor_poll(void)
Check for filesystem changes.
Definition: monitor.c:397
static int mutt_dlg_dopager_observer(struct NotifyCallback *nc)
Listen for config changes affecting the dopager menus - Implements observer_t.
Definition: curs_lib.c:627
void * global_data
Data from notify_observer_add()
Definition: observer.h:44
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
Window has a fixed size.
Definition: mutt_window.h:44
Plain text.
Definition: color.h:77
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
struct MuttWindow * win_pager
Definition: pager.h:76
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
int mutt_buffer_enter_fname_full(const char *prompt, struct Buffer *fname, bool mailbox, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:747
void mutt_window_reflow_message_rows(int mw_rows)
Resize the Message Window.
Definition: mutt_window.c:458
Keep our place when entering a string.
Definition: enter_state.h:32
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:57
#define mutt_b2s(buf)
Definition: buffer.h:41
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:912
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:106
struct Notify * notify_new(void)
Create a new notifications handler.
Definition: notify.c:49
WHERE bool OptForceRefresh
(pseudo) refresh even during macros
Definition: options.h:37
Prototypes for many functions.
void mutt_window_get_coords(struct MuttWindow *win, int *col, int *row)
Get the cursor position in the Window.
Definition: mutt_window.c:298
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:113
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:546
static struct KeyEvent * UngetKeyEvents
Definition: curs_lib.c:89
int mutt_buffer_get_field_full(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:257
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1338
void mutt_format_s_x(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
Format a string like snprintf()
Definition: curs_lib.c:1186
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:49
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_enter_state_free(struct EnterState **ptr)
Free an EnterState.
Definition: enter.c:832
WHERE char ErrorBuf[256]
Copy of the last error message.
Definition: globals.h:46
char * data
Pointer to data.
Definition: buffer.h:35
WHERE short C_Timeout
Config: Time to wait for user input in menus.
Definition: globals.h:147
uint16_t PagerFlags
Flags for mutt_pager(), e.g. MUTT_SHOWFLAT.
Definition: pager.h:42
static int mutt_monitor_getch(void)
Get a character and poll the filesystem monitor.
Definition: curs_lib.c:156
size_t mutt_wstr_trunc(const char *src, size_t maxlen, size_t maxwid, size_t *width)
Work out how to truncate a widechar string.
Definition: curs_lib.c:1288
WHERE bool ErrorBufMessage
true if the last message was an error
Definition: globals.h:45
GUI present the user with a selectable list.
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
Pager Dialog, mutt_do_pager()
Definition: mutt_window.h:81
An event such as a keypress.
Definition: keymap.h:61
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:187
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
Definition: color.h:129
Color and attribute parsing.
int mutt_strnwidth(const char *s, size_t n)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1351
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: browser.h:46
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition: keymap.c:147
bool notify_observer_add(struct Notify *notify, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:153
#define MUTT_FILE
Do file completion.
Definition: mutt.h:58
int mutt_get_field_unbuffered(const char *msg, char *buf, size_t buflen, CompletionFlags flags)
Ask the user for a string (ignoring macro buffer)
Definition: curs_lib.c:332
void * event_data
Data from notify_send()
Definition: observer.h:43
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:564
Restore the previous cursor state.
Definition: mutt_curses.h:79
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:36
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: browser.h:45
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:138
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:579
Window containing paged free-form text.
Definition: mutt_window.h:96
static size_t MacroBufferLen
Definition: curs_lib.c:81
Colour indicator.
Definition: mutt_menu.h:74
GUI display a file/email/help in a viewport with paging.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:639
int mutt_window_addch(int ch)
Write one character to a Window.
Definition: mutt_window.c:491
#define MUTT_EFILE
Do file completion, plus incoming folders.
Definition: mutt.h:59
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:1223
Error message.
Definition: color.h:70
Log at debug level 1.
Definition: logging.h:40
int n
Definition: acutest.h:492
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:665
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:432
#define mutt_error(...)
Definition: logging.h:84
void mutt_flush_unget_to_endcond(void)
Clear entries from UngetKeyEvents.
Definition: curs_lib.c:886
void mutt_getch_timeout(int delay)
Set the getch() timeout.
Definition: curs_lib.c:144
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1425
#define FREE(x)
Definition: memory.h:40
WHERE bool OptMsgErr
(pseudo) used by mutt_error/mutt_message
Definition: options.h:41
WHERE bool C_Beep
Config: Make a noise when an error occurs.
Definition: globals.h:200
Monitor files for changes.
struct MuttWindowList children
Children Windows.
Definition: mutt_window.h:121
#define EILSEQ
Definition: charset.c:49
void mutt_unget_string(const char *s)
Return a string to the input buffer.
Definition: curs_lib.c:832
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:185
void mutt_show_error(void)
Show the user an error message.
Definition: curs_lib.c:532
struct MuttWindow * win_ibar
Definition: pager.h:73
WHERE char * C_Pager
Config: External command for viewing messages, or &#39;builtin&#39; to use NeoMutt&#39;s.
Definition: globals.h:128
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:82
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:46
int mutt_window_addstr(const char *str)
Write a string to a Window.
Definition: mutt_window.c:521
struct EnterState * mutt_enter_state_new(void)
Create a new EnterState.
Definition: enter.c:126
Options in prompt.
Definition: color.h:78
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int const char * file
Definition: acutest.h:617
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:131
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1103
int mutt_pager(const char *banner, const char *fname, PagerFlags flags, struct Pager *extra)
Display a file, or help, in a window.
Definition: pager.c:2204
Convenience wrapper for the library headers.
Window wants as much space as possible.
Definition: mutt_window.h:45
WHERE bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program ...
Definition: options.h:39
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:128
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:125
const char * name
Name of config item that changed.
Definition: subset.h:73
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:353
bool C_MetaKey
Config: Interpret &#39;ALT-x&#39; as &#39;ESC-x&#39;.
Definition: curs_lib.c:70
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
Question/user input.
Definition: color.h:80
int MuttGetchTimeout
Timeout in ms for mutt_getch()
Definition: curs_lib.c:91
void mutt_format_s_tree(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string with tree characters.
Definition: curs_lib.c:1235
static size_t UngetLen
Definition: curs_lib.c:88
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:1072
int mutt_addwch(wchar_t wc)
addwch would be provided by an up-to-date curses library
Definition: curs_lib.c:1038
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
int mutt_get_field_full(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:308
struct MuttWindow * win_pbar
Definition: pager.h:75
uint8_t SelectFileFlags
Flags for mutt_select_file(), e.g. MUTT_SEL_MAILBOX.
Definition: browser.h:43