1 /* $Id: sys.c,v 1.37 2020-11-02 23:20:52 phil Exp $ */
2 
3 /* support for HOST() on Win32 pb 12/22/97 */
4 
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif /* HAVE_CONFIG_H defined */
8 
9 #include <windows.h>
10 #include <stdio.h>
11 
12 #include "h.h"
13 #include "snotypes.h"
14 #include "lib.h"
15 #include "str.h"
16 
17 void
hwname(char * cp)18 hwname(char *cp) {
19     char *hw;
20     SYSTEM_INFO si;
21 
22     GetSystemInfo(&si);			/* no return value */
23 
24     switch (si.wProcessorArchitecture) {
25     case PROCESSOR_ARCHITECTURE_INTEL:
26 	/*
27 	 * wProcessorLevel, not used on Windows 95.
28 	 * dwProcessorType contains mnemonic values, but is obsolete on WinNT!
29 	 */
30 	hw = "x86";
31 	break;
32 
33     case PROCESSOR_ARCHITECTURE_MIPS:
34 	hw = "mips";
35 	break;
36 
37     case PROCESSOR_ARCHITECTURE_ALPHA:
38 	hw = "alpha";
39 	break;
40 
41     case PROCESSOR_ARCHITECTURE_PPC:
42 	hw = "ppc";
43 	break;
44 
45 #ifdef PROCESSOR_ARCHITECTURE_IA64
46     case PROCESSOR_ARCHITECTURE_IA64:
47 	hw = "ia64";
48 	break;
49 #endif
50 
51 #ifdef PROCESSOR_ARCHITECTURE_AMD64
52     case PROCESSOR_ARCHITECTURE_AMD64:
53 	hw = "amd64";
54 	break;
55 #endif
56 
57 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
58     case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
59 	hw = "WOW64";
60 	break;
61 #endif
62 
63 #ifdef PROCESSOR_ARCHITECTURE_ARM
64     case PROCESSOR_ARCHITECTURE_ARM:
65 	hw = "arm";
66 	break;
67 #endif
68 
69     default:
70 	sprintf(cp, "arch#%d", si.wProcessorArchitecture);
71 	return;
72     }
73     strcpy(cp, hw);
74 }
75 
76 void
osname(char * cp)77 osname(char *cp) {
78     char osname[32], *os;
79     OSVERSIONINFOEXA osv;
80     int server = 0;
81     int build = 0;
82     int vnum = 0;
83 
84     ZeroMemory(&osv, sizeof(osv));
85     osv.dwOSVersionInfoSize = sizeof(osv);
86     /*
87      * https://docs.microsoft.com/en-us/windows/win32/sysinfo/targeting-your-application-at-windows-8-1
88      * 5/31/2018:
89      * In Windows 8.1 and Windows 10, the GetVersion and GetVersionEx
90      * functions have been deprecated. In Windows 10, the
91      * VerifyVersionInfo function has also been deprecated. While you
92      * can still call the deprecated functions, if your application
93      * does not specifically target Windows 8.1 or Windows 10, the
94      * functions will return the Windows 8 version (6.2).
95      */
96 
97     /*
98      * PLB 11/2/2020:
99      * Aparently there's an undocumented interface in NTDLL that's used my the MSVCRT:
100      * extern VOID WINAPI RtlGetNtVersionNumbers(LPDWORD pMajor, LPDWORD pMinor, LPDWORD pBuild);
101      *
102      * Also "the kernel-mode equivalent of the user-mode GetVersionEx function in the Windows SDK":
103      * RtlGetVersion
104      */
105 
106     /* uncharmingly, GetVersionExA wants a OSVERSIONINFOA
107      * but OSVERSIONINFOEXA doesn't start with one!!
108      */
109     if (!GetVersionExA((LPOSVERSIONINFO)&osv)) {
110 	strcpy(cp, "Win????");
111 	return;
112     }
113 #ifdef DEBUG_SYS
114     printf("plat %ld %ld.%ld.%ld ptype %d\n",
115 	   osv.dwPlatformId,
116 	   osv.dwMajorVersion,
117 	   osv.dwMinorVersion,
118 	   osv.dwBuildNumber,
119 	   osv.wProductType);
120 #define HERE printf("line %d\n", __LINE__)
121 #else
122 #define HERE (void)0
123 #endif
124     build = osv.dwBuildNumber;
125     server = (osv.wProductType != VER_NT_WORKSTATION);
126     switch (osv.dwPlatformId) {
127     case VER_PLATFORM_WIN32s:
128 	os = "Win32s";
129 	break;
130 
131     case VER_PLATFORM_WIN32_WINDOWS:
132 	/*
133 	 * If the dwPlatformId member of that structure is
134 	 * VER_PLATFORM_WIN32_WINDOWS, and the low word of the
135 	 * dwBuildNumber member is "1111," the system is running
136 	 * Windows 95 OSR 2. For Windows 95 and Windows 95 OSR 2, the
137 	 * dwMajorVersion element returns "4" and dwMinorVersion
138 	 * returns "0." Future versions or OSRs of Windows 95 will
139 	 * have higher build numbers. They may also have higher
140 	 * major/minor version numbers.
141 	 */
142 	os = "Win??";
143 	build &= 0xffff;
144 	if (osv.dwMajorVersion == 4) {
145 	    switch (osv.dwMinorVersion) {
146 	    case 0:
147 		os = "Win95";
148 		if (osv.szCSDVersion[1] == 'A' ||
149 		    osv.szCSDVersion[1] == 'B') {
150 		    os = "Win95 OSR2";
151 		    osv.szCSDVersion[0] = '\0';
152 		}
153 		break;
154 	    case 10:
155 		os = "Win98";
156 		if (osv.szCSDVersion[1] == 'A') {
157 		    os = "Win98SE";
158 		    osv.szCSDVersion[0] = '\0';
159 		}
160 		break;
161 	    case 90:
162 		os = "WinME";
163 		break;
164 	    default:
165 		vnum = 1;
166 		HERE;
167 		break;
168 	    }
169 	}
170 	break;
171 
172     case VER_PLATFORM_WIN32_NT:
173 	/* also osv.wProductType, wSuiteMask */
174 	os = "WinNT";
175 	switch (osv.dwMajorVersion) {
176 	case 5:
177 	    switch (osv.dwMinorVersion) {
178 	    case 0:
179 		os = "Win2K";
180 		break;
181 	    case 1:
182 		os = "WinXP";
183 		break;
184 	    case 2:
185 		os = "WinServer2003";
186 		break;
187 	    default:
188 		vnum = 1;
189 		HERE;
190 		break;
191 	    } // 5
192 	    break;
193 
194 	case 6:				/* "Longhorn" family */
195 	    switch (osv.dwMinorVersion) {
196 	    case 0:
197 		if (server)
198 		    os = "WinServer2008";
199 		else
200 		    os = "WinVista";
201 		break;
202 	    case 1:
203 		if (server)
204 		    os = "WinServer2008R2";
205 		else
206 		    os = "Win7";
207 		break;
208 	    case 2:
209 		if (server)
210 		    os = "WinServer2012";
211 		else
212 		    os = "Win8";
213 		break;
214 	    case 3:	/* not returned unless manifested (see above) */
215 		if (server)
216 		    os = "WinServer2012R2";
217 		else
218 		    os = "Win8.1";
219 		break;
220 	    case 4:	/* prior to build 9926 (only if manifested) */
221 		if (server)
222 		    os = "WinServer2016";
223 		else
224 		    os = "Win10";
225 		break;
226 	    default:
227 		vnum = 1;
228 		HERE;
229 		break;
230 	    } // 6
231 	    break;
232 
233 	case 10: /* not returned unless binary manifested for Win10 (else 6.2) */
234 	    switch (osv.dwMinorVersion) {
235 	    case 0:
236 		if (server)
237 		    os = "WinServer2016"; /* 2019 if build >=1809? */
238 		else
239 		    os = "Win10";
240 		break;
241 	    /*
242 	     * anything added here will not be seen unless snobol4.exe.manifest
243 	     * updated with guid of new OS
244 	     */
245 	    default:
246 		vnum = 1;
247 		HERE;
248 		break;
249 	    } // 10
250 	    break;
251 
252 	default:
253 	    vnum = 1;
254 	    HERE;
255 	    break;
256 	} // dwMajorVersion
257 	break;
258 
259     default:
260 	sprintf(osname, "Win#%d", (int)osv.dwPlatformId);
261 	os = osname;
262 	vnum = 1;
263 	HERE;
264 	break;
265     } // dwPlatformId
266 
267     if (vnum) {
268 	sprintf(cp, "%s %d.%d", os, (int)osv.dwMajorVersion, (int)osv.dwMinorVersion);
269 	if (build) {
270 	    cp += strlen(cp);
271 	    sprintf(cp, ".%d", build);
272 	}
273 	if (server)
274 	    strcat(cp, " server");
275     }
276     else
277 	strcpy(cp, os);
278 
279     cp += strlen(cp);
280 
281     /*
282      * szCSDVersion:
283      *
284      * Windows NT: Contains a null-terminated string, such as "Service
285      * Pack 3", that indicates the latest Service Pack installed on
286      * the system. If no Service Pack has been installed, the string
287      * is empty.
288      *
289      * Windows 95: Contains a null-terminated string that provides
290      * arbitrary additional information about the operating system.
291      */
292     if (osv.szCSDVersion[0]) {
293 	char *tp;
294 
295 	/* strip trailing spaces, if any */
296 	tp = osv.szCSDVersion + strlen(osv.szCSDVersion);
297 	while (tp > osv.szCSDVersion && tp[-1] == ' ')
298 	    tp--;
299 	*tp = '\0';
300 
301 	/* strip leading spaces, if any */
302 	tp = osv.szCSDVersion;
303 	while (*tp && *tp == ' ')
304 	    tp++;
305 
306 	/* ignore if empty */
307 	if (*tp) {
308 	    *cp++ = ' ';
309 	    while ((*cp++ = *tp++))
310 		;
311 	}
312     }
313 }
314