NeoMutt  2025-12-11-435-g4ac674
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
version.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include <sys/utsname.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "gui/lib.h"
38#include "version.h"
39#include "compress/lib.h"
40#include "store/lib.h"
41#include "globals.h"
42#ifdef HAVE_LIBIDN
43#include "address/lib.h"
44#endif
45#ifdef CRYPT_BACKEND_GPGME
46#include "ncrypt/lib.h"
47#endif
48#ifdef HAVE_NOTMUCH
49#include <notmuch.h>
50#endif
51#ifdef USE_SSL_OPENSSL
52#include <openssl/opensslv.h>
53#endif
54#ifdef USE_SSL_GNUTLS
55#include <gnutls/gnutls.h>
56#endif
57#ifdef HAVE_PCRE2
59#define PCRE2_CODE_UNIT_WIDTH 8
60#include <pcre2.h>
61#endif
62
64static const int SCREEN_WIDTH = 80;
65
66extern unsigned char cc_cflags[];
67extern unsigned char configure_options[];
68
70static const char *Copyright =
71 "Copyright (C) 2015-2026 Richard Russon <rich@flatcap.org>\n"
72 "Copyright (C) 2016-2025 Pietro Cerutti <gahr@gahr.ch>\n"
73 "Copyright (C) 2017-2019 Mehdi Abaakouk <sileht@sileht.net>\n"
74 "Copyright (C) 2018-2020 Federico Kircheis <federico.kircheis@gmail.com>\n"
75 "Copyright (C) 2017-2022 Austin Ray <austin@austinray.io>\n"
76 "Copyright (C) 2023-2025 Dennis Schön <mail@dennis-schoen.de>\n"
77 "Copyright (C) 2016-2017 Damien Riegel <damien.riegel@gmail.com>\n"
78 "Copyright (C) 2023-2025 Rayford Shireman\n"
79 "Copyright (C) 2021-2023 David Purton <dcpurton@marshwiggle.net>\n"
80 "Copyright (C) 2020-2023 наб <nabijaczleweli@nabijaczleweli.xyz>\n";
81
83static const char *Thanks = N_(
84 "Many others not mentioned here contributed code, fixes and suggestions.\n");
85
87static const char *License = N_(
88 "This program is free software; you can redistribute it and/or modify\n"
89 "it under the terms of the GNU General Public License as published by\n"
90 "the Free Software Foundation; either version 2 of the License, or\n"
91 "(at your option) any later version.\n"
92 "\n"
93 "This program is distributed in the hope that it will be useful,\n"
94 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
95 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
96 "GNU General Public License for more details.\n"
97 "\n"
98 "You should have received a copy of the GNU General Public License\n"
99 "along with this program; if not, write to the Free Software\n"
100 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n");
101
103static const char *ReachingUs = N_("To learn more about NeoMutt, visit: https://neomutt.org\n"
104 "If you find a bug in NeoMutt, please raise an issue at:\n"
105 " https://github.com/neomutt/neomutt/issues\n"
106 "or send an email to: <neomutt-devel@neomutt.org>\n");
107
108// clang-format off
110static const char *Notice1 = N_("Copyright (C) 2015-2026 Richard Russon and friends");
111static const char *Notice2 = N_("NeoMutt is free software, provided without warranty: `neomutt -vv` for details");
112// clang-format on
113
114/* These are sorted by the display string */
116static const struct CompileOption CompOpts[] = {
117#ifdef USE_AUTOCRYPT
118 { "autocrypt", 1 },
119#else
120 { "autocrypt", 0 },
121#endif
122#ifdef USE_FCNTL
123 { "fcntl", 1 },
124#else
125 { "fcntl", 0 },
126#endif
127#ifdef USE_FLOCK
128 { "flock", 1 },
129#else
130 { "flock", 0 },
131#endif
132#ifdef USE_FMEMOPEN
133 { "fmemopen", 1 },
134#else
135 { "fmemopen", 0 },
136#endif
137#ifdef HAVE_FUTIMENS
138 { "futimens", 1 },
139#else
140 { "futimens", 0 },
141#endif
142#ifdef HAVE_GETADDRINFO
143 { "getaddrinfo", 1 },
144#else
145 { "getaddrinfo", 0 },
146#endif
147#ifdef USE_SSL_GNUTLS
148 { "gnutls", 1 },
149#else
150 { "gnutls", 0 },
151#endif
152#ifdef CRYPT_BACKEND_GPGME
153 { "gpgme", 1 },
154#else
155 { "gpgme", 0 },
156#endif
157#ifdef USE_SASL_GNU
158 { "gsasl", 1 },
159#else
160 { "gsasl", 0 },
161#endif
162#ifdef USE_GSS
163 { "gss", 1 },
164#else
165 { "gss", 0 },
166#endif
167#ifdef USE_HCACHE
168 { "hcache", 1 },
169#else
170 { "hcache", 0 },
171#endif
172#ifdef HOMESPOOL
173 { "homespool", 1 },
174#else
175 { "homespool", 0 },
176#endif
177#ifdef HAVE_LIBIDN
178 { "idn", 1 },
179#else
180 { "idn", 0 },
181#endif
182#ifdef USE_INOTIFY
183 { "inotify", 1 },
184#else
185 { "inotify", 0 },
186#endif
187#ifdef LOCALES_HACK
188 { "locales_hack", 1 },
189#else
190 { "locales_hack", 0 },
191#endif
192#ifdef USE_LUA
193 { "lua", 1 },
194#else
195 { "lua", 0 },
196#endif
197#ifdef ENABLE_NLS
198 { "nls", 1 },
199#else
200 { "nls", 0 },
201#endif
202#ifdef USE_NOTMUCH
203 { "notmuch", 1 },
204#else
205 { "notmuch", 0 },
206#endif
207#ifdef USE_SSL_OPENSSL
208 { "openssl", 1 },
209#else
210 { "openssl", 0 },
211#endif
212#ifdef HAVE_PCRE2
213 { "pcre2", 1 },
214#endif
215#ifdef CRYPT_BACKEND_CLASSIC_PGP
216 { "pgp", 1 },
217#else
218 { "pgp", 0 },
219#endif
220#ifndef HAVE_PCRE2
221 { "regex", 1 },
222#endif
223#ifdef USE_SASL_CYRUS
224 { "sasl", 1 },
225#else
226 { "sasl", 0 },
227#endif
228#ifdef CRYPT_BACKEND_CLASSIC_SMIME
229 { "smime", 1 },
230#else
231 { "smime", 0 },
232#endif
233#ifdef USE_SQLITE
234 { "sqlite", 1 },
235#else
236 { "sqlite", 0 },
237#endif
238#ifdef NEOMUTT_DIRECT_COLORS
239 { "truecolor", 1 },
240#else
241 { "truecolor", 0 },
242#endif
243 { NULL, 0 },
244};
245
247static const struct CompileOption DevelOpts[] = {
248#ifdef USE_ASAN
249 { "asan", 2 },
250#endif
251#ifdef USE_DEBUG_BACKTRACE
252 { "backtrace", 2 },
253#endif
254#ifdef USE_DEBUG_COLOR
255 { "color", 2 },
256#endif
257#ifdef USE_DEBUG_EMAIL
258 { "email", 2 },
259#endif
260#ifdef USE_DEBUG_GRAPHVIZ
261 { "graphviz", 2 },
262#endif
263#ifdef USE_DEBUG_KEYMAP
264 { "keymap", 2 },
265#endif
266#ifdef USE_DEBUG_LOGGING
267 { "logging", 2 },
268#endif
269#ifdef USE_DEBUG_NAMES
270 { "names", 2 },
271#endif
272#ifdef USE_DEBUG_NOTIFY
273 { "notify", 2 },
274#endif
275#ifdef QUEUE_MACRO_DEBUG_TRACE
276 { "queue", 2 },
277#endif
278#ifdef USE_UBSAN
279 { "ubsan", 2 },
280#endif
281#ifdef USE_DEBUG_WINDOW
282 { "window", 2 },
283#endif
284 { NULL, 0 },
285};
286
293const char *mutt_make_version(void)
294{
295 static char vstring[256];
296 snprintf(vstring, sizeof(vstring), "%s%s", PACKAGE_VERSION, GitVer);
297 return vstring;
298}
299
307static char *rstrip_in_place(char *s)
308{
309 if (!s)
310 return NULL;
311
312 char *p = &s[strlen(s)];
313 if (p == s)
314 return s;
315 p--;
316 while ((p >= s) && ((*p == '\n') || (*p == '\r')))
317 *p-- = '\0';
318 return s;
319}
320
325static void system_get(struct KeyValueArray *kva)
326{
327 struct Buffer *buf = buf_pool_get();
328 struct KeyValue kv = { 0 };
329
330 struct utsname uts = { 0 };
331 uname(&uts);
332
333#ifdef SCO
334 buf_printf(buf, "SCO %s", uts.release);
335#else
336 buf_printf(buf, "%s %s", uts.sysname, uts.release);
337#endif
338 buf_add_printf(buf, " (%s)", uts.machine);
339
340 kv.key = mutt_str_dup("System");
341 kv.value = buf_strdup(buf);
342 ARRAY_ADD(kva, kv);
343
344 buf_strcpy(buf, curses_version());
345#ifdef NCURSES_VERSION
346 buf_add_printf(buf, " (compiled with %s.%d)", NCURSES_VERSION, NCURSES_VERSION_PATCH);
347#endif
348 kv.key = mutt_str_dup("ncurses");
349 kv.value = buf_strdup(buf);
350 ARRAY_ADD(kva, kv);
351
352#ifdef _LIBICONV_VERSION
353 buf_printf(buf, "%d.%d", _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 0xff);
354 kv.key = mutt_str_dup("libiconv");
355 kv.value = buf_strdup(buf);
356 ARRAY_ADD(kva, kv);
357#endif
358
359#ifdef HAVE_LIBIDN
360 kv.key = mutt_str_dup("libidn2");
362 ARRAY_ADD(kva, kv);
363#endif
364
365#ifdef CRYPT_BACKEND_GPGME
366 kv.key = mutt_str_dup("GPGME");
368 ARRAY_ADD(kva, kv);
369#endif
370
371#ifdef USE_SSL_OPENSSL
372#ifdef LIBRESSL_VERSION_TEXT
373 kv.key = mutt_str_dup("LibreSSL");
374 kv.value = mutt_str_dup(LIBRESSL_VERSION_TEXT);
375#endif
376#ifdef OPENSSL_VERSION_TEXT
377 kv.key = mutt_str_dup("OpenSSL");
378 kv.value = mutt_str_dup(OPENSSL_VERSION_TEXT);
379#endif
380 ARRAY_ADD(kva, kv);
381#endif
382
383#ifdef USE_SSL_GNUTLS
384 kv.key = mutt_str_dup("GnuTLS");
385 kv.value = mutt_str_dup(GNUTLS_VERSION);
386 ARRAY_ADD(kva, kv);
387#endif
388
389#ifdef HAVE_NOTMUCH
390 buf_printf(buf, "%d.%d.%d", LIBNOTMUCH_MAJOR_VERSION,
391 LIBNOTMUCH_MINOR_VERSION, LIBNOTMUCH_MICRO_VERSION);
392 kv.key = mutt_str_dup("libnotmuch");
393 kv.value = buf_strdup(buf);
394 ARRAY_ADD(kva, kv);
395#endif
396
397#ifdef HAVE_PCRE2
398 char version[24] = { 0 };
399 pcre2_config(PCRE2_CONFIG_VERSION, version);
400 kv.key = mutt_str_dup("PCRE2");
401 kv.value = mutt_str_dup(version);
402 ARRAY_ADD(kva, kv);
403#endif
404
405 buf_pool_release(&buf);
406}
407
412static void paths_get(struct KeyValueArray *kva)
413{
414 struct KeyValue kv = { 0 };
415
416#ifdef DOMAIN
417 kv.key = mutt_str_dup("DOMAIN");
418 kv.value = mutt_str_dup(DOMAIN);
419 ARRAY_ADD(kva, kv);
420#endif
421
422#ifdef ISPELL
423 kv.key = mutt_str_dup("ISPELL");
425 ARRAY_ADD(kva, kv);
426#endif
427 kv.key = mutt_str_dup("MAILPATH");
428 kv.value = mutt_str_dup(MAILPATH);
429 ARRAY_ADD(kva, kv);
430
431 kv.key = mutt_str_dup("PKGDATADIR");
432 kv.value = mutt_str_dup(PKGDATADIR);
433 ARRAY_ADD(kva, kv);
434
435 kv.key = mutt_str_dup("SENDMAIL");
436 kv.value = mutt_str_dup(SENDMAIL);
437 ARRAY_ADD(kva, kv);
438
439 kv.key = mutt_str_dup("SYSCONFDIR");
440 kv.value = mutt_str_dup(SYSCONFDIR);
441 ARRAY_ADD(kva, kv);
442}
443
450static void kva_clear(struct KeyValueArray *kva)
451{
452 struct KeyValue *kv = NULL;
453
454 ARRAY_FOREACH(kv, kva)
455 {
456 FREE(&kv->key);
457 FREE(&kv->value);
458 }
459
460 ARRAY_FREE(kva);
461}
462
468{
469 struct NeoMuttVersion *ver = MUTT_MEM_CALLOC(1, struct NeoMuttVersion);
470
472
473 ARRAY_INIT(&ver->system);
474 system_get(&ver->system);
475
476#ifdef USE_HCACHE
478#ifdef USE_HCACHE_COMPRESSION
479 ver->compression = compress_list();
480#endif
481#endif
482
485
486 rstrip_in_place((char *) cc_cflags);
488
489 ver->feature = CompOpts;
490
491 if (DevelOpts[0].name)
492 ver->devel = DevelOpts;
493
494 ARRAY_INIT(&ver->paths);
495 paths_get(&ver->paths);
496
497 return ver;
498}
499
504void version_free(struct NeoMuttVersion **ptr)
505{
506 if (!ptr || !*ptr)
507 return;
508
509 struct NeoMuttVersion *ver = *ptr;
510
511 FREE(&ver->version);
512
513 kva_clear(&ver->system);
514 kva_clear(&ver->paths);
515
516 slist_free(&ver->storage);
517 slist_free(&ver->compression);
518 slist_free(&ver->configure);
519 slist_free(&ver->compilation);
520
521 FREE(ptr);
522}
523
537static void print_compile_options(const struct CompileOption *co, FILE *fp, bool use_ansi)
538{
539 if (!co || !fp)
540 return;
541
542 size_t used = 2;
543 fprintf(fp, " ");
544 for (int i = 0; co[i].name; i++)
545 {
546 const size_t len = strlen(co[i].name) + 2; /* +/- and a space */
547 if ((used + len) > SCREEN_WIDTH)
548 {
549 used = 2;
550 fprintf(fp, "\n ");
551 }
552 used += len;
553 const char *fmt = "?%s ";
554 switch (co[i].enabled)
555 {
556 case 0: // Disabled
557 if (use_ansi)
558 fmt = "\033[1;31m-%s\033[0m "; // Escape, red
559 else
560 fmt = "-%s ";
561 break;
562 case 1: // Enabled
563 if (use_ansi)
564 fmt = "\033[1;32m+%s\033[0m "; // Escape, green
565 else
566 fmt = "+%s ";
567 break;
568 case 2: // Devel only
569 if (use_ansi)
570 fmt = "\033[1;36m%s\033[0m "; // Escape, cyan
571 else
572 fmt = "%s ";
573 break;
574 }
575 fprintf(fp, fmt, co[i].name);
576 }
577 fprintf(fp, "\n");
578}
579
589bool print_version(FILE *fp, bool use_ansi)
590{
591 if (!fp)
592 return false;
593
594 struct KeyValue *kv = NULL;
595 struct ListNode *np = NULL;
596 struct NeoMuttVersion *ver = version_get();
597
598 const char *col_cyan = "";
599 const char *col_bold = "";
600 const char *col_end = "";
601
602 if (use_ansi)
603 {
604 col_cyan = "\033[1;36m"; // Escape, cyan
605 col_bold = "\033[1m"; // Escape, bold
606 col_end = "\033[0m"; // Escape, end
607 }
608
609 fprintf(fp, "%sNeoMutt %s%s\n", col_cyan, ver->version, col_end);
610 fprintf(fp, "%s\n", _(Notice1));
611 fprintf(fp, "%s\n\n", _(Notice2));
612
613 ARRAY_FOREACH(kv, &ver->system)
614 {
615 fprintf(fp, "%s%s:%s %s\n", col_bold, kv->key, col_end, kv->value);
616 }
617
618 if (ver->storage)
619 {
620 fprintf(fp, "%sstorage:%s ", col_bold, col_end);
621 STAILQ_FOREACH(np, &ver->storage->head, entries)
622 {
623 fputs(np->data, fp);
624 if (STAILQ_NEXT(np, entries))
625 fputs(", ", fp);
626 }
627 fputs("\n", fp);
628 }
629
630 if (ver->compression)
631 {
632 fprintf(fp, "%scompression:%s ", col_bold, col_end);
633 STAILQ_FOREACH(np, &ver->compression->head, entries)
634 {
635 fputs(np->data, fp);
636 if (STAILQ_NEXT(np, entries))
637 fputs(", ", fp);
638 }
639 fputs("\n", fp);
640 }
641 fputs("\n", fp);
642
643 fprintf(fp, "%sConfigure options:%s ", col_bold, col_end);
644 if (ver->configure)
645 {
646 STAILQ_FOREACH(np, &ver->configure->head, entries)
647 {
648 if (!np || !np->data)
649 continue;
650 fputs(np->data, fp);
651 if (STAILQ_NEXT(np, entries))
652 fputs(" ", fp);
653 }
654 }
655 fputs("\n\n", fp);
656
657 if (ver->compilation)
658 {
659 fprintf(fp, "%sCompilation CFLAGS:%s ", col_bold, col_end);
660 STAILQ_FOREACH(np, &ver->compilation->head, entries)
661 {
662 if (!np || !np->data)
663 continue;
664 fputs(np->data, fp);
665 if (STAILQ_NEXT(np, entries))
666 fputs(" ", fp);
667 }
668 fputs("\n\n", fp);
669 }
670
671 fprintf(fp, "%s%s%s\n", col_bold, _("Compile options:"), col_end);
672 print_compile_options(ver->feature, fp, use_ansi);
673 fputs("\n", fp);
674
675 if (ver->devel)
676 {
677 fprintf(fp, "%s%s%s\n", col_bold, _("Devel options:"), col_end);
678 print_compile_options(ver->devel, fp, use_ansi);
679 fputs("\n", fp);
680 }
681
682 ARRAY_FOREACH(kv, &ver->paths)
683 {
684 fprintf(fp, "%s%s%s=\"%s\"\n", col_bold, kv->key, col_end, kv->value);
685 }
686 fputs("\n", fp);
687
688 fputs(_(ReachingUs), fp);
689
690 version_free(&ver);
691 return true;
692}
693
702{
703 printf("NeoMutt %s\n", mutt_make_version());
704 puts(Copyright);
705 puts(_(Thanks));
706 puts(_(License));
707 puts(_(ReachingUs));
708
709 fflush(stdout);
710 return !ferror(stdout);
711}
712
728bool feature_enabled(const char *name)
729{
730 if (!name)
731 return false;
732 for (int i = 0; CompOpts[i].name; i++)
733 {
734 if (mutt_str_equal(name, CompOpts[i].name))
735 {
736 return CompOpts[i].enabled;
737 }
738 }
739 return false;
740}
Email Address Handling.
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_INIT(head)
Initialize an array.
Definition array.h:65
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
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
#define ISPELL
Definition config.c:40
struct Slist * compress_list(void)
Get a list of compression backend names.
Definition compress.c:59
API for the header cache compression.
Convenience wrapper for the config headers.
const char * mutt_gpgme_print_version(void)
Get version of GPGME.
Global variables.
const char * GitVer
Convenience wrapper for the gui headers.
const char * mutt_idna_print_version(void)
Create an IDN version string.
Definition idna.c:272
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
Convenience wrapper for the library headers.
#define N_(a)
Definition message.h:32
#define _(a)
Definition message.h:28
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition slist.c:177
void slist_free(struct Slist **ptr)
Free an Slist object.
Definition slist.c:124
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
API for encryption/signing of emails.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
Key value store.
struct Slist * store_backend_list(void)
Get a list of backend names.
Definition store.c:85
String manipulation buffer.
Definition buffer.h:36
Built-in capability.
Definition version.h:44
const char * name
Option name.
Definition version.h:45
Key/Value pairs.
Definition version.h:34
const char * key
Key name.
Definition version.h:35
const char * value
Key value.
Definition version.h:36
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Version info about NeoMutt.
Definition version.h:53
struct KeyValueArray paths
Compiled-in paths.
Definition version.h:67
struct Slist * configure
Configure options.
Definition version.h:61
const char * version
Version of NeoMutt: YYYYMMDD-NUM-HASH (number of commits, git hash)
Definition version.h:54
struct Slist * compression
Compression methods, e.g. zlib.
Definition version.h:59
struct Slist * storage
Storage backends, e.g. lmdb.
Definition version.h:58
const struct CompileOption * devel
Compiled-in development features.
Definition version.h:65
const struct CompileOption * feature
Compiled-in features.
Definition version.h:64
struct Slist * compilation
Compilation CFLAGS.
Definition version.h:62
struct KeyValueArray system
System information.
Definition version.h:56
struct ListHead head
List containing values.
Definition slist.h:38
#define D_SLIST_SEP_SPACE
Slist items are space-separated.
Definition types.h:110
static const struct CompileOption DevelOpts[]
Devel options strings for neomutt -v output.
Definition version.c:247
static void paths_get(struct KeyValueArray *kva)
Get compiled-in paths.
Definition version.c:412
static const char * Thanks
CLI Version: Thanks.
Definition version.c:83
static const char * License
CLI Version: License.
Definition version.c:87
static const char * Copyright
CLI Version: Authors' copyrights.
Definition version.c:70
static const int SCREEN_WIDTH
CLI: Width to wrap version info.
Definition version.c:64
void version_free(struct NeoMuttVersion **ptr)
Free a NeoMuttVersion.
Definition version.c:504
static const char * ReachingUs
CLI Version: How to reach the NeoMutt Team.
Definition version.c:103
static const char * Notice1
CLI Version: Warranty notice.
Definition version.c:110
const char * mutt_make_version(void)
Generate the NeoMutt version string.
Definition version.c:293
bool print_copyright(void)
Print copyright message.
Definition version.c:701
unsigned char configure_options[]
bool print_version(FILE *fp, bool use_ansi)
Print system and compile info to a file.
Definition version.c:589
static const char * Notice2
Definition version.c:111
static void system_get(struct KeyValueArray *kva)
Get info about system libraries.
Definition version.c:325
static void kva_clear(struct KeyValueArray *kva)
Free the strings of a KeyValueArray.
Definition version.c:450
unsigned char cc_cflags[]
static char * rstrip_in_place(char *s)
Strip a trailing carriage return.
Definition version.c:307
bool feature_enabled(const char *name)
Test if a compile-time feature is enabled.
Definition version.c:728
struct NeoMuttVersion * version_get(void)
Get NeoMutt version info.
Definition version.c:467
static const struct CompileOption CompOpts[]
Compile options strings for neomutt -v output.
Definition version.c:116
static void print_compile_options(const struct CompileOption *co, FILE *fp, bool use_ansi)
Print a list of enabled/disabled features.
Definition version.c:537
Display version and copyright about NeoMutt.