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