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