Fix handling of --extcap-version with an argument.
[metze/wireshark/wip.git] / version_info.c
1 /* version_info.c
2  * Routines to report version information for Wireshark programs
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include <config.h>
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <locale.h>
17
18 #ifdef _WIN32
19 #include <windows.h>
20 #elif __APPLE__
21 #include <sys/types.h>
22 #include <sys/sysctl.h>
23 #elif __linux__
24 #include <sys/sysinfo.h>
25 #endif
26
27 #include <glib.h>
28
29 #ifdef HAVE_ZLIB
30 #include <zlib.h>
31 #endif
32
33 #include "version.h"
34
35 #include "version_info.h"
36
37 #include <wsutil/cpu_info.h>
38 #include <wsutil/copyright_info.h>
39 #include <wsutil/os_version_info.h>
40 #include <wsutil/ws_printf.h> /* ws_debug_printf */
41 #include <wsutil/plugins.h>
42
43 /*
44  * If the string doesn't end with a newline, append one.
45  * Then word-wrap it to 80 columns.
46  */
47 static void
48 end_string(GString *str)
49 {
50         size_t point;
51         char *p, *q;
52
53         point = str->len;
54         if (point == 0 || str->str[point - 1] != '\n')
55                 g_string_append(str, "\n");
56         p = str->str;
57         while (*p != '\0') {
58                 q = strchr(p, '\n');
59                 if (q - p > 80) {
60                         /*
61                          * Break at or before this point.
62                          */
63                         q = p + 80;
64                         while (q > p && *q != ' ')
65                                 q--;
66                         if (q != p)
67                                 *q = '\n';
68                 }
69                 p = q + 1;
70         }
71 }
72
73 static const gchar *
74 get_zlib_compiled_version_info(void)
75 {
76 #ifdef HAVE_ZLIB
77 #ifdef ZLIB_VERSION
78         return "with zlib "ZLIB_VERSION;
79 #else
80         return "with zlib (version unknown)";
81 #endif /* ZLIB_VERSION */
82 #else
83         return "without zlib";
84 #endif /* HAVE_ZLIB */
85 }
86
87 /*
88  * Get various library compile-time versions, put them in a GString,
89  * and return the GString.
90  *
91  * "prepend_info" is called at the start to prepend any additional
92  * information before the standard library information.
93  *
94  * "append_info" is called at the end to append any additional
95  * information after the standard library information.  This is
96  * required in order to, for example, put the Portaudio information
97  * at the end of the string, as we currently don't use Portaudio in
98  * TShark.
99  */
100 GString *
101 get_compiled_version_info(void (*prepend_info)(GString *),
102                           void (*append_info)(GString *))
103 {
104         GString *str;
105
106         str = g_string_new("Compiled ");
107
108         if (sizeof(str) == 4)
109                 g_string_append(str, "(32-bit) ");
110         else
111                 g_string_append(str, "(64-bit) ");
112
113         if (prepend_info) {
114                 (*prepend_info)(str);
115                 g_string_append(str, ", ");
116         }
117
118         /* GLIB */
119         g_string_append(str, "with ");
120         g_string_append_printf(str,
121 #ifdef GLIB_MAJOR_VERSION
122             "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
123             GLIB_MICRO_VERSION);
124 #else
125             "GLib (version unknown)");
126 #endif
127
128         g_string_append_printf(str, ", %s", get_zlib_compiled_version_info());
129
130         /* Additional application-dependent information */
131         if (append_info)
132                 (*append_info)(str);
133         g_string_append(str, ".");
134
135         end_string(str);
136
137         return str;
138 }
139
140 static void
141 get_mem_info(GString *str)
142 {
143         gint64 memsize = 0;
144
145 #ifdef _WIN32
146         MEMORYSTATUSEX statex;
147
148         statex.dwLength = sizeof (statex);
149
150         if (GlobalMemoryStatusEx(&statex))
151                 memsize = statex.ullTotalPhys;
152 #elif __APPLE__
153         size_t len = sizeof(memsize);
154         sysctlbyname("hw.memsize", &memsize, &len, NULL, 0);
155 #elif __linux__
156         struct sysinfo info;
157         if (sysinfo(&info) == 0)
158                 memsize = info.totalram * info.mem_unit;
159 #endif
160
161         if (memsize > 0)
162                 g_string_append_printf(str, ", with ""%" G_GINT64_MODIFIER "d" " MB of physical memory", memsize/(1024*1024));
163 }
164
165 /*
166  * Get compiler information, and append it to the GString.
167  */
168 static void
169 get_compiler_info(GString *str)
170 {
171         /*
172          * See https://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers
173          * information on various defined strings.
174          *
175          * GCC's __VERSION__ is a nice text string for humans to
176          * read.  The page at sourceforge.net largely describes
177          * numeric #defines that encode the version; if the compiler
178          * doesn't also offer a nice printable string, we try prettifying
179          * the number somehow.
180          */
181 #if defined(__GNUC__) && defined(__VERSION__)
182         /*
183          * Clang and llvm-gcc also define __GNUC__ and __VERSION__;
184          * distinguish between them.
185          */
186 #if defined(__clang__)
187         /*
188          * Microsoft have a version of their compiler that has Clang
189          * as the front end and their code generator as the back end.
190          *
191          * My head asplode.
192          */
193   #if defined(__MSC_VER)
194         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d.%d clang/C2 %s and -fno-ms-compatibility.\n",
195             (_MSC_VER / 100) - 6, _MSC_VER % 100, __VERSION__);
196   #else
197         g_string_append_printf(str, "\n\nBuilt using clang %s.\n", __VERSION__);
198   #endif /* defined(__MSC_VER) */
199 #elif defined(__llvm__)
200         g_string_append_printf(str, "\n\nBuilt using llvm-gcc %s.\n", __VERSION__);
201 #else /* boring old GCC */
202         g_string_append_printf(str, "\n\nBuilt using gcc %s.\n", __VERSION__);
203 #endif /* llvm */
204 #elif defined(__HP_aCC)
205         g_string_append_printf(str, "\n\nBuilt using HP aCC %d.\n", __HP_aCC);
206 #elif defined(__xlC__)
207         g_string_append_printf(str, "\n\nBuilt using IBM XL C %d.%d\n",
208             (__xlC__ >> 8) & 0xFF, __xlC__ & 0xFF);
209 #ifdef __IBMC__
210         if ((__IBMC__ % 10) != 0)
211                 g_string_append_printf(str, " patch %d", __IBMC__ % 10);
212 #endif /* __IBMC__ */
213         g_string_append_printf(str, "\n");
214 #elif defined(__INTEL_COMPILER)
215         g_string_append_printf(str, "\n\nBuilt using Intel C %d.%d",
216             __INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10);
217         if ((__INTEL_COMPILER % 10) != 0)
218                 g_string_append_printf(str, " patch %d", __INTEL_COMPILER % 10);
219 #ifdef __INTEL_COMPILER_BUILD_DATE
220         g_string_sprinta(str, ", compiler built %04d-%02d-%02d",
221             __INTEL_COMPILER_BUILD_DATE / 10000,
222             (__INTEL_COMPILER_BUILD_DATE / 100) % 100,
223             __INTEL_COMPILER_BUILD_DATE % 100);
224 #endif /* __INTEL_COMPILER_BUILD_DATE */
225         g_string_append_printf(str, "\n");
226 #elif defined(_MSC_FULL_VER)
227 # if _MSC_FULL_VER > 99999999
228         /* Quote from the web:
229          * Bakersfield: DevDiv's upper management determines the scheduling of new major versions.
230          * They also decided to increment the product version from 12 (for VS 2013) to 14 (for VS 2015).
231          * However, the C++ compiler's version incremented normally, from 18 to 19.
232          * (It's larger because the C++ compiler predates the "Visual" in Visual C++.)
233          * XXX? Should we just output the compiler version?
234          */
235     int compiler_major_version = (_MSC_FULL_VER / 10000000), visual_studio_ver;
236
237     if (compiler_major_version < 19) {
238         visual_studio_ver = compiler_major_version - 6;
239     }else{
240         visual_studio_ver = compiler_major_version - 5;
241     }
242
243     g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d",
244                    visual_studio_ver,
245                                (_MSC_FULL_VER / 100000) % 100);
246 #  if (_MSC_FULL_VER % 100000) != 0
247         g_string_append_printf(str, " build %d",
248                                _MSC_FULL_VER % 100000);
249 #  endif
250 # else
251         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d",
252                                (_MSC_FULL_VER / 1000000) - 6,
253                                (_MSC_FULL_VER / 10000) % 100);
254 #  if (_MSC_FULL_VER % 10000) != 0
255         g_string_append_printf(str, " build %d",
256                                _MSC_FULL_VER % 10000);
257 #  endif
258 # endif
259         g_string_append_printf(str, "\n");
260 #elif defined(_MSC_VER)
261         /* _MSC_FULL_VER not defined, but _MSC_VER defined */
262   #if defined(__clang__)
263         /* More head asplosion; see above. */
264         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d.%d clang/C2 %s.\n",
265             (_MSC_VER / 100) - 6, _MSC_VER % 100, __VERSION__);
266   #else
267         g_string_append_printf(str, "\n\nBuilt using clang %s.\n", __VERSION__);
268   #endif /* defined(__MSC_VER) */
269         g_string_append_printf(str, "\n\nBuilt using Microsoft Visual C++ %d.%d\n",
270             (_MSC_VER / 100) - 6, _MSC_VER % 100);
271 #elif defined(__SUNPRO_C)
272         g_string_append_printf(str, "\n\nBuilt using Sun C %d.%d",
273             (__SUNPRO_C >> 8) & 0xF, (__SUNPRO_C >> 4) & 0xF);
274         if ((__SUNPRO_C & 0xF) != 0)
275                 g_string_append_printf(str, " patch %d", __SUNPRO_C & 0xF);
276         g_string_append_printf(str, "\n");
277 #endif
278 }
279
280 /* XXX - is the setlocale() return string opaque? For glibc the separator is ';' */
281 static gchar *
282 get_locale(void)
283 {
284         const gchar *lang;
285         gchar **locv, *loc;
286
287         lang = setlocale(LC_ALL, NULL);
288         if (lang == NULL) {
289                 return NULL;
290         }
291
292         locv = g_strsplit(lang, ";", -1);
293         loc = g_strjoinv(", ", locv);
294         g_strfreev(locv);
295         return loc;
296 }
297
298 /*
299  * Get various library run-time versions, and the OS version, and append
300  * them to the specified GString.
301  *
302  * "additional_info" is called at the end to append any additional
303  * information; this is required in order to, for example, put the
304  * Portaudio information at the end of the string, as we currently
305  * don't use Portaudio in TShark.
306  */
307 GString *
308 get_runtime_version_info(void (*additional_info)(GString *))
309 {
310         GString *str;
311         gchar *lang;
312
313         str = g_string_new("Running on ");
314
315         get_os_version_info(str);
316
317         /* CPU Info */
318         get_cpu_info(str);
319
320         /* Get info about installed memory */
321         get_mem_info(str);
322
323         /*
324          * Locale.
325          *
326          * This returns the C language's locale information; this
327          * returns the locale that's actually in effect, even if
328          * it doesn't happen to match the settings of any of the
329          * locale environment variables.
330          *
331          * On Windows get_locale returns the full language, country
332          * name, and code page, e.g. "English_United States.1252":
333          * https://msdn.microsoft.com/en-us/library/x99tb11d.aspx
334          */
335         if ((lang = get_locale()) != NULL) {
336                 g_string_append_printf(str, ", with locale %s", lang);
337                 g_free(lang);
338         }
339         else {
340                 g_string_append(str, ", with default locale");
341         }
342
343
344         /* Additional application-dependent information */
345         if (additional_info)
346                 (*additional_info)(str);
347
348         /* zlib */
349 #if defined(HAVE_ZLIB) && !defined(_WIN32)
350         g_string_append_printf(str, ", with zlib %s", zlibVersion());
351 #endif
352
353         /* plugins */
354 #ifdef HAVE_PLUGINS
355         if (g_module_supported()) {
356                 g_string_append_printf(str, ", binary plugins supported (%d loaded)", plugins_get_count());
357         }
358         else {
359                 g_string_append(str, ", binary plugins not supported");
360         }
361 #endif
362
363         g_string_append(str, ".");
364
365         /* Compiler info */
366         get_compiler_info(str);
367
368         end_string(str);
369
370         return str;
371 }
372
373 void
374 show_version(const gchar *prog_name_str, GString *comp_info_str,
375              GString *runtime_info_str)
376 {
377         ws_debug_printf("%s %s\n"
378                "\n"
379                "%s"
380                "\n"
381                "%s"
382                "\n"
383                "%s",
384                prog_name_str, get_ws_vcs_version_info(), get_copyright_info(),
385                comp_info_str->str, runtime_info_str->str);
386 }
387
388 /*
389  * Return a version number string for Wireshark, including, for builds
390  * from a tree checked out from Wireshark's version control system,
391  * something identifying what version was checked out.
392  */
393 const char *
394 get_ws_vcs_version_info(void)
395 {
396 #ifdef VCSVERSION
397         return VERSION " (" VCSVERSION ")";
398 #else
399         return VERSION;
400 #endif
401 }
402
403 void
404 get_ws_version_number(int *major, int *minor, int *micro)
405 {
406         if (major)
407                 *major = VERSION_MAJOR;
408         if (minor)
409                 *minor = VERSION_MINOR;
410         if (micro)
411                 *micro = VERSION_MICRO;
412 }
413
414 /*
415  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
416  *
417  * Local variables:
418  * c-basic-offset: 8
419  * tab-width: 8
420  * indent-tabs-mode: t
421  * End:
422  *
423  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
424  * :indentSize=8:tabSize=8:noTabs=false:
425  */