1076b9443SCy Schubert /*
2076b9443SCy Schubert * ----------------------------------------------------------------------------
3076b9443SCy Schubert * nmakehlp.c --
4076b9443SCy Schubert *
5076b9443SCy Schubert * This is used to fix limitations within nmake and the environment.
6076b9443SCy Schubert *
7076b9443SCy Schubert * Copyright (c) 2002 by David Gravereaux.
8076b9443SCy Schubert * Copyright (c) 2006 by Pat Thoyts
9076b9443SCy Schubert *
10076b9443SCy Schubert * See the file "license.terms" for information on usage and redistribution of
11076b9443SCy Schubert * this file, and for a DISCLAIMER OF ALL WARRANTIES.
12076b9443SCy Schubert * ----------------------------------------------------------------------------
13076b9443SCy Schubert */
14076b9443SCy Schubert
15076b9443SCy Schubert #define _CRT_SECURE_NO_DEPRECATE
16076b9443SCy Schubert #include <windows.h>
17*0197ba46SCy Schubert #ifdef _MSC_VER
18076b9443SCy Schubert #pragma comment (lib, "user32.lib")
19076b9443SCy Schubert #pragma comment (lib, "kernel32.lib")
20*0197ba46SCy Schubert #endif
21076b9443SCy Schubert #include <stdio.h>
22076b9443SCy Schubert #include <math.h>
23076b9443SCy Schubert
24076b9443SCy Schubert /*
25076b9443SCy Schubert * This library is required for x64 builds with _some_ versions of MSVC
26076b9443SCy Schubert */
27076b9443SCy Schubert #if defined(_M_IA64) || defined(_M_AMD64)
28076b9443SCy Schubert #if _MSC_VER >= 1400 && _MSC_VER < 1500
29076b9443SCy Schubert #pragma comment(lib, "bufferoverflowU")
30076b9443SCy Schubert #endif
31076b9443SCy Schubert #endif
32076b9443SCy Schubert
33076b9443SCy Schubert /* ISO hack for dumb VC++ */
34076b9443SCy Schubert #ifdef _MSC_VER
35076b9443SCy Schubert #define snprintf _snprintf
36076b9443SCy Schubert #endif
37076b9443SCy Schubert
38076b9443SCy Schubert
39076b9443SCy Schubert /* protos */
40076b9443SCy Schubert
41076b9443SCy Schubert static int CheckForCompilerFeature(const char *option);
42*0197ba46SCy Schubert static int CheckForLinkerFeature(char **options, int count);
43076b9443SCy Schubert static int IsIn(const char *string, const char *substring);
44076b9443SCy Schubert static int SubstituteFile(const char *substs, const char *filename);
45076b9443SCy Schubert static int QualifyPath(const char *path);
46*0197ba46SCy Schubert static int LocateDependency(const char *keyfile);
47*0197ba46SCy Schubert static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
48076b9443SCy Schubert static DWORD WINAPI ReadFromPipe(LPVOID args);
49076b9443SCy Schubert
50076b9443SCy Schubert /* globals */
51076b9443SCy Schubert
52076b9443SCy Schubert #define CHUNK 25
53076b9443SCy Schubert #define STATICBUFFERSIZE 1000
54076b9443SCy Schubert typedef struct {
55076b9443SCy Schubert HANDLE pipe;
56076b9443SCy Schubert char buffer[STATICBUFFERSIZE];
57076b9443SCy Schubert } pipeinfo;
58076b9443SCy Schubert
59*0197ba46SCy Schubert pipeinfo Out = {INVALID_HANDLE_VALUE, ""};
60*0197ba46SCy Schubert pipeinfo Err = {INVALID_HANDLE_VALUE, ""};
61076b9443SCy Schubert
62076b9443SCy Schubert /*
63076b9443SCy Schubert * exitcodes: 0 == no, 1 == yes, 2 == error
64076b9443SCy Schubert */
65076b9443SCy Schubert
66076b9443SCy Schubert int
main(int argc,char * argv[])67076b9443SCy Schubert main(
68076b9443SCy Schubert int argc,
69076b9443SCy Schubert char *argv[])
70076b9443SCy Schubert {
71076b9443SCy Schubert char msg[300];
72076b9443SCy Schubert DWORD dwWritten;
73076b9443SCy Schubert int chars;
74*0197ba46SCy Schubert const char *s;
75076b9443SCy Schubert
76076b9443SCy Schubert /*
77076b9443SCy Schubert * Make sure children (cl.exe and link.exe) are kept quiet.
78076b9443SCy Schubert */
79076b9443SCy Schubert
80076b9443SCy Schubert SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
81076b9443SCy Schubert
82076b9443SCy Schubert /*
83076b9443SCy Schubert * Make sure the compiler and linker aren't effected by the outside world.
84076b9443SCy Schubert */
85076b9443SCy Schubert
86076b9443SCy Schubert SetEnvironmentVariable("CL", "");
87076b9443SCy Schubert SetEnvironmentVariable("LINK", "");
88076b9443SCy Schubert
89076b9443SCy Schubert if (argc > 1 && *argv[1] == '-') {
90076b9443SCy Schubert switch (*(argv[1]+1)) {
91076b9443SCy Schubert case 'c':
92076b9443SCy Schubert if (argc != 3) {
93076b9443SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
94076b9443SCy Schubert "usage: %s -c <compiler option>\n"
95076b9443SCy Schubert "Tests for whether cl.exe supports an option\n"
96076b9443SCy Schubert "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
97076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
98076b9443SCy Schubert &dwWritten, NULL);
99076b9443SCy Schubert return 2;
100076b9443SCy Schubert }
101076b9443SCy Schubert return CheckForCompilerFeature(argv[2]);
102076b9443SCy Schubert case 'l':
103*0197ba46SCy Schubert if (argc < 3) {
104076b9443SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
105*0197ba46SCy Schubert "usage: %s -l <linker option> ?<mandatory option> ...?\n"
106076b9443SCy Schubert "Tests for whether link.exe supports an option\n"
107076b9443SCy Schubert "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
108076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
109076b9443SCy Schubert &dwWritten, NULL);
110076b9443SCy Schubert return 2;
111076b9443SCy Schubert }
112*0197ba46SCy Schubert return CheckForLinkerFeature(&argv[2], argc-2);
113076b9443SCy Schubert case 'f':
114076b9443SCy Schubert if (argc == 2) {
115076b9443SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
116076b9443SCy Schubert "usage: %s -f <string> <substring>\n"
117076b9443SCy Schubert "Find a substring within another\n"
118076b9443SCy Schubert "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
119076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
120076b9443SCy Schubert &dwWritten, NULL);
121076b9443SCy Schubert return 2;
122076b9443SCy Schubert } else if (argc == 3) {
123076b9443SCy Schubert /*
124076b9443SCy Schubert * If the string is blank, there is no match.
125076b9443SCy Schubert */
126076b9443SCy Schubert
127076b9443SCy Schubert return 0;
128076b9443SCy Schubert } else {
129076b9443SCy Schubert return IsIn(argv[2], argv[3]);
130076b9443SCy Schubert }
131076b9443SCy Schubert case 's':
132076b9443SCy Schubert if (argc == 2) {
133076b9443SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
134076b9443SCy Schubert "usage: %s -s <substitutions file> <file>\n"
135076b9443SCy Schubert "Perform a set of string map type substutitions on a file\n"
136076b9443SCy Schubert "exitcodes: 0\n",
137076b9443SCy Schubert argv[0]);
138076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
139076b9443SCy Schubert &dwWritten, NULL);
140076b9443SCy Schubert return 2;
141076b9443SCy Schubert }
142076b9443SCy Schubert return SubstituteFile(argv[2], argv[3]);
143076b9443SCy Schubert case 'V':
144076b9443SCy Schubert if (argc != 4) {
145076b9443SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
146076b9443SCy Schubert "usage: %s -V filename matchstring\n"
147076b9443SCy Schubert "Extract a version from a file:\n"
148076b9443SCy Schubert "eg: pkgIndex.tcl \"package ifneeded http\"",
149076b9443SCy Schubert argv[0]);
150076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
151076b9443SCy Schubert &dwWritten, NULL);
152076b9443SCy Schubert return 0;
153076b9443SCy Schubert }
154*0197ba46SCy Schubert s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
155*0197ba46SCy Schubert if (s && *s) {
156*0197ba46SCy Schubert printf("%s\n", s);
157076b9443SCy Schubert return 0;
158*0197ba46SCy Schubert } else
159*0197ba46SCy Schubert return 1; /* Version not found. Return non-0 exit code */
160*0197ba46SCy Schubert
161076b9443SCy Schubert case 'Q':
162076b9443SCy Schubert if (argc != 3) {
163076b9443SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
164076b9443SCy Schubert "usage: %s -Q path\n"
165076b9443SCy Schubert "Emit the fully qualified path\n"
166076b9443SCy Schubert "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
167076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
168076b9443SCy Schubert &dwWritten, NULL);
169076b9443SCy Schubert return 2;
170076b9443SCy Schubert }
171076b9443SCy Schubert return QualifyPath(argv[2]);
172*0197ba46SCy Schubert
173*0197ba46SCy Schubert case 'L':
174*0197ba46SCy Schubert if (argc != 3) {
175*0197ba46SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
176*0197ba46SCy Schubert "usage: %s -L keypath\n"
177*0197ba46SCy Schubert "Emit the fully qualified path of directory containing keypath\n"
178*0197ba46SCy Schubert "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
179*0197ba46SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
180*0197ba46SCy Schubert &dwWritten, NULL);
181*0197ba46SCy Schubert return 2;
182*0197ba46SCy Schubert }
183*0197ba46SCy Schubert return LocateDependency(argv[2]);
184076b9443SCy Schubert }
185076b9443SCy Schubert }
186076b9443SCy Schubert chars = snprintf(msg, sizeof(msg) - 1,
187076b9443SCy Schubert "usage: %s -c|-f|-l|-Q|-s|-V ...\n"
188076b9443SCy Schubert "This is a little helper app to equalize shell differences between WinNT and\n"
189076b9443SCy Schubert "Win9x and get nmake.exe to accomplish its job.\n",
190076b9443SCy Schubert argv[0]);
191076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
192076b9443SCy Schubert return 2;
193076b9443SCy Schubert }
194076b9443SCy Schubert
195076b9443SCy Schubert static int
CheckForCompilerFeature(const char * option)196076b9443SCy Schubert CheckForCompilerFeature(
197076b9443SCy Schubert const char *option)
198076b9443SCy Schubert {
199076b9443SCy Schubert STARTUPINFO si;
200076b9443SCy Schubert PROCESS_INFORMATION pi;
201076b9443SCy Schubert SECURITY_ATTRIBUTES sa;
202076b9443SCy Schubert DWORD threadID;
203076b9443SCy Schubert char msg[300];
204076b9443SCy Schubert BOOL ok;
205076b9443SCy Schubert HANDLE hProcess, h, pipeThreads[2];
206076b9443SCy Schubert char cmdline[100];
207076b9443SCy Schubert
208076b9443SCy Schubert hProcess = GetCurrentProcess();
209076b9443SCy Schubert
210076b9443SCy Schubert ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
211076b9443SCy Schubert ZeroMemory(&si, sizeof(STARTUPINFO));
212076b9443SCy Schubert si.cb = sizeof(STARTUPINFO);
213076b9443SCy Schubert si.dwFlags = STARTF_USESTDHANDLES;
214076b9443SCy Schubert si.hStdInput = INVALID_HANDLE_VALUE;
215076b9443SCy Schubert
216076b9443SCy Schubert ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
217076b9443SCy Schubert sa.nLength = sizeof(SECURITY_ATTRIBUTES);
218076b9443SCy Schubert sa.lpSecurityDescriptor = NULL;
219076b9443SCy Schubert sa.bInheritHandle = FALSE;
220076b9443SCy Schubert
221076b9443SCy Schubert /*
222076b9443SCy Schubert * Create a non-inheritible pipe.
223076b9443SCy Schubert */
224076b9443SCy Schubert
225076b9443SCy Schubert CreatePipe(&Out.pipe, &h, &sa, 0);
226076b9443SCy Schubert
227076b9443SCy Schubert /*
228076b9443SCy Schubert * Dupe the write side, make it inheritible, and close the original.
229076b9443SCy Schubert */
230076b9443SCy Schubert
231076b9443SCy Schubert DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
232076b9443SCy Schubert DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
233076b9443SCy Schubert
234076b9443SCy Schubert /*
235076b9443SCy Schubert * Same as above, but for the error side.
236076b9443SCy Schubert */
237076b9443SCy Schubert
238076b9443SCy Schubert CreatePipe(&Err.pipe, &h, &sa, 0);
239076b9443SCy Schubert DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
240076b9443SCy Schubert DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
241076b9443SCy Schubert
242076b9443SCy Schubert /*
243076b9443SCy Schubert * Base command line.
244076b9443SCy Schubert */
245076b9443SCy Schubert
246076b9443SCy Schubert lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");
247076b9443SCy Schubert
248076b9443SCy Schubert /*
249076b9443SCy Schubert * Append our option for testing
250076b9443SCy Schubert */
251076b9443SCy Schubert
252076b9443SCy Schubert lstrcat(cmdline, option);
253076b9443SCy Schubert
254076b9443SCy Schubert /*
255076b9443SCy Schubert * Filename to compile, which exists, but is nothing and empty.
256076b9443SCy Schubert */
257076b9443SCy Schubert
258076b9443SCy Schubert lstrcat(cmdline, " .\\nul");
259076b9443SCy Schubert
260076b9443SCy Schubert ok = CreateProcess(
261076b9443SCy Schubert NULL, /* Module name. */
262076b9443SCy Schubert cmdline, /* Command line. */
263076b9443SCy Schubert NULL, /* Process handle not inheritable. */
264076b9443SCy Schubert NULL, /* Thread handle not inheritable. */
265076b9443SCy Schubert TRUE, /* yes, inherit handles. */
266076b9443SCy Schubert DETACHED_PROCESS, /* No console for you. */
267076b9443SCy Schubert NULL, /* Use parent's environment block. */
268076b9443SCy Schubert NULL, /* Use parent's starting directory. */
269076b9443SCy Schubert &si, /* Pointer to STARTUPINFO structure. */
270076b9443SCy Schubert &pi); /* Pointer to PROCESS_INFORMATION structure. */
271076b9443SCy Schubert
272076b9443SCy Schubert if (!ok) {
273076b9443SCy Schubert DWORD err = GetLastError();
274076b9443SCy Schubert int chars = snprintf(msg, sizeof(msg) - 1,
275076b9443SCy Schubert "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
276076b9443SCy Schubert
277076b9443SCy Schubert FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
278*0197ba46SCy Schubert FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
279076b9443SCy Schubert (300-chars), 0);
280076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
281076b9443SCy Schubert return 2;
282076b9443SCy Schubert }
283076b9443SCy Schubert
284076b9443SCy Schubert /*
285076b9443SCy Schubert * Close our references to the write handles that have now been inherited.
286076b9443SCy Schubert */
287076b9443SCy Schubert
288076b9443SCy Schubert CloseHandle(si.hStdOutput);
289076b9443SCy Schubert CloseHandle(si.hStdError);
290076b9443SCy Schubert
291076b9443SCy Schubert WaitForInputIdle(pi.hProcess, 5000);
292076b9443SCy Schubert CloseHandle(pi.hThread);
293076b9443SCy Schubert
294076b9443SCy Schubert /*
295076b9443SCy Schubert * Start the pipe reader threads.
296076b9443SCy Schubert */
297076b9443SCy Schubert
298076b9443SCy Schubert pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
299076b9443SCy Schubert pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
300076b9443SCy Schubert
301076b9443SCy Schubert /*
302076b9443SCy Schubert * Block waiting for the process to end.
303076b9443SCy Schubert */
304076b9443SCy Schubert
305076b9443SCy Schubert WaitForSingleObject(pi.hProcess, INFINITE);
306076b9443SCy Schubert CloseHandle(pi.hProcess);
307076b9443SCy Schubert
308076b9443SCy Schubert /*
309076b9443SCy Schubert * Wait for our pipe to get done reading, should it be a little slow.
310076b9443SCy Schubert */
311076b9443SCy Schubert
312076b9443SCy Schubert WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
313076b9443SCy Schubert CloseHandle(pipeThreads[0]);
314076b9443SCy Schubert CloseHandle(pipeThreads[1]);
315076b9443SCy Schubert
316076b9443SCy Schubert /*
317076b9443SCy Schubert * Look for the commandline warning code in both streams.
318076b9443SCy Schubert * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
319076b9443SCy Schubert */
320076b9443SCy Schubert
321076b9443SCy Schubert return !(strstr(Out.buffer, "D4002") != NULL
322076b9443SCy Schubert || strstr(Err.buffer, "D4002") != NULL
323076b9443SCy Schubert || strstr(Out.buffer, "D9002") != NULL
324076b9443SCy Schubert || strstr(Err.buffer, "D9002") != NULL
325076b9443SCy Schubert || strstr(Out.buffer, "D2021") != NULL
326076b9443SCy Schubert || strstr(Err.buffer, "D2021") != NULL);
327076b9443SCy Schubert }
328076b9443SCy Schubert
329076b9443SCy Schubert static int
CheckForLinkerFeature(char ** options,int count)330076b9443SCy Schubert CheckForLinkerFeature(
331*0197ba46SCy Schubert char **options,
332*0197ba46SCy Schubert int count)
333076b9443SCy Schubert {
334076b9443SCy Schubert STARTUPINFO si;
335076b9443SCy Schubert PROCESS_INFORMATION pi;
336076b9443SCy Schubert SECURITY_ATTRIBUTES sa;
337076b9443SCy Schubert DWORD threadID;
338076b9443SCy Schubert char msg[300];
339076b9443SCy Schubert BOOL ok;
340076b9443SCy Schubert HANDLE hProcess, h, pipeThreads[2];
341*0197ba46SCy Schubert int i;
342*0197ba46SCy Schubert char cmdline[255];
343076b9443SCy Schubert
344076b9443SCy Schubert hProcess = GetCurrentProcess();
345076b9443SCy Schubert
346076b9443SCy Schubert ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
347076b9443SCy Schubert ZeroMemory(&si, sizeof(STARTUPINFO));
348076b9443SCy Schubert si.cb = sizeof(STARTUPINFO);
349076b9443SCy Schubert si.dwFlags = STARTF_USESTDHANDLES;
350076b9443SCy Schubert si.hStdInput = INVALID_HANDLE_VALUE;
351076b9443SCy Schubert
352076b9443SCy Schubert ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
353076b9443SCy Schubert sa.nLength = sizeof(SECURITY_ATTRIBUTES);
354076b9443SCy Schubert sa.lpSecurityDescriptor = NULL;
355076b9443SCy Schubert sa.bInheritHandle = TRUE;
356076b9443SCy Schubert
357076b9443SCy Schubert /*
358076b9443SCy Schubert * Create a non-inheritible pipe.
359076b9443SCy Schubert */
360076b9443SCy Schubert
361076b9443SCy Schubert CreatePipe(&Out.pipe, &h, &sa, 0);
362076b9443SCy Schubert
363076b9443SCy Schubert /*
364076b9443SCy Schubert * Dupe the write side, make it inheritible, and close the original.
365076b9443SCy Schubert */
366076b9443SCy Schubert
367076b9443SCy Schubert DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
368076b9443SCy Schubert DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
369076b9443SCy Schubert
370076b9443SCy Schubert /*
371076b9443SCy Schubert * Same as above, but for the error side.
372076b9443SCy Schubert */
373076b9443SCy Schubert
374076b9443SCy Schubert CreatePipe(&Err.pipe, &h, &sa, 0);
375076b9443SCy Schubert DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
376076b9443SCy Schubert DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
377076b9443SCy Schubert
378076b9443SCy Schubert /*
379076b9443SCy Schubert * Base command line.
380076b9443SCy Schubert */
381076b9443SCy Schubert
382076b9443SCy Schubert lstrcpy(cmdline, "link.exe -nologo ");
383076b9443SCy Schubert
384076b9443SCy Schubert /*
385076b9443SCy Schubert * Append our option for testing.
386076b9443SCy Schubert */
387076b9443SCy Schubert
388*0197ba46SCy Schubert for (i = 0; i < count; i++) {
389*0197ba46SCy Schubert lstrcat(cmdline, " \"");
390*0197ba46SCy Schubert lstrcat(cmdline, options[i]);
391*0197ba46SCy Schubert lstrcat(cmdline, "\"");
392*0197ba46SCy Schubert }
393076b9443SCy Schubert
394076b9443SCy Schubert ok = CreateProcess(
395076b9443SCy Schubert NULL, /* Module name. */
396076b9443SCy Schubert cmdline, /* Command line. */
397076b9443SCy Schubert NULL, /* Process handle not inheritable. */
398076b9443SCy Schubert NULL, /* Thread handle not inheritable. */
399076b9443SCy Schubert TRUE, /* yes, inherit handles. */
400076b9443SCy Schubert DETACHED_PROCESS, /* No console for you. */
401076b9443SCy Schubert NULL, /* Use parent's environment block. */
402076b9443SCy Schubert NULL, /* Use parent's starting directory. */
403076b9443SCy Schubert &si, /* Pointer to STARTUPINFO structure. */
404076b9443SCy Schubert &pi); /* Pointer to PROCESS_INFORMATION structure. */
405076b9443SCy Schubert
406076b9443SCy Schubert if (!ok) {
407076b9443SCy Schubert DWORD err = GetLastError();
408076b9443SCy Schubert int chars = snprintf(msg, sizeof(msg) - 1,
409076b9443SCy Schubert "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
410076b9443SCy Schubert
411076b9443SCy Schubert FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
412*0197ba46SCy Schubert FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
413076b9443SCy Schubert (300-chars), 0);
414076b9443SCy Schubert WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
415076b9443SCy Schubert return 2;
416076b9443SCy Schubert }
417076b9443SCy Schubert
418076b9443SCy Schubert /*
419076b9443SCy Schubert * Close our references to the write handles that have now been inherited.
420076b9443SCy Schubert */
421076b9443SCy Schubert
422076b9443SCy Schubert CloseHandle(si.hStdOutput);
423076b9443SCy Schubert CloseHandle(si.hStdError);
424076b9443SCy Schubert
425076b9443SCy Schubert WaitForInputIdle(pi.hProcess, 5000);
426076b9443SCy Schubert CloseHandle(pi.hThread);
427076b9443SCy Schubert
428076b9443SCy Schubert /*
429076b9443SCy Schubert * Start the pipe reader threads.
430076b9443SCy Schubert */
431076b9443SCy Schubert
432076b9443SCy Schubert pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
433076b9443SCy Schubert pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
434076b9443SCy Schubert
435076b9443SCy Schubert /*
436076b9443SCy Schubert * Block waiting for the process to end.
437076b9443SCy Schubert */
438076b9443SCy Schubert
439076b9443SCy Schubert WaitForSingleObject(pi.hProcess, INFINITE);
440076b9443SCy Schubert CloseHandle(pi.hProcess);
441076b9443SCy Schubert
442076b9443SCy Schubert /*
443076b9443SCy Schubert * Wait for our pipe to get done reading, should it be a little slow.
444076b9443SCy Schubert */
445076b9443SCy Schubert
446076b9443SCy Schubert WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
447076b9443SCy Schubert CloseHandle(pipeThreads[0]);
448076b9443SCy Schubert CloseHandle(pipeThreads[1]);
449076b9443SCy Schubert
450076b9443SCy Schubert /*
451076b9443SCy Schubert * Look for the commandline warning code in the stderr stream.
452076b9443SCy Schubert */
453076b9443SCy Schubert
454076b9443SCy Schubert return !(strstr(Out.buffer, "LNK1117") != NULL ||
455076b9443SCy Schubert strstr(Err.buffer, "LNK1117") != NULL ||
456076b9443SCy Schubert strstr(Out.buffer, "LNK4044") != NULL ||
457*0197ba46SCy Schubert strstr(Err.buffer, "LNK4044") != NULL ||
458*0197ba46SCy Schubert strstr(Out.buffer, "LNK4224") != NULL ||
459*0197ba46SCy Schubert strstr(Err.buffer, "LNK4224") != NULL);
460076b9443SCy Schubert }
461076b9443SCy Schubert
462076b9443SCy Schubert static DWORD WINAPI
ReadFromPipe(LPVOID args)463076b9443SCy Schubert ReadFromPipe(
464076b9443SCy Schubert LPVOID args)
465076b9443SCy Schubert {
466076b9443SCy Schubert pipeinfo *pi = (pipeinfo *) args;
467076b9443SCy Schubert char *lastBuf = pi->buffer;
468076b9443SCy Schubert DWORD dwRead;
469076b9443SCy Schubert BOOL ok;
470076b9443SCy Schubert
471076b9443SCy Schubert again:
472076b9443SCy Schubert if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
473076b9443SCy Schubert CloseHandle(pi->pipe);
474076b9443SCy Schubert return (DWORD)-1;
475076b9443SCy Schubert }
476076b9443SCy Schubert ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
477076b9443SCy Schubert if (!ok || dwRead == 0) {
478076b9443SCy Schubert CloseHandle(pi->pipe);
479076b9443SCy Schubert return 0;
480076b9443SCy Schubert }
481076b9443SCy Schubert lastBuf += dwRead;
482076b9443SCy Schubert goto again;
483076b9443SCy Schubert
484076b9443SCy Schubert return 0; /* makes the compiler happy */
485076b9443SCy Schubert }
486076b9443SCy Schubert
487076b9443SCy Schubert static int
IsIn(const char * string,const char * substring)488076b9443SCy Schubert IsIn(
489076b9443SCy Schubert const char *string,
490076b9443SCy Schubert const char *substring)
491076b9443SCy Schubert {
492076b9443SCy Schubert return (strstr(string, substring) != NULL);
493076b9443SCy Schubert }
494076b9443SCy Schubert
495076b9443SCy Schubert /*
496076b9443SCy Schubert * GetVersionFromFile --
497076b9443SCy Schubert * Looks for a match string in a file and then returns the version
498076b9443SCy Schubert * following the match where a version is anything acceptable to
499076b9443SCy Schubert * package provide or package ifneeded.
500076b9443SCy Schubert */
501076b9443SCy Schubert
502076b9443SCy Schubert static const char *
GetVersionFromFile(const char * filename,const char * match,int numdots)503076b9443SCy Schubert GetVersionFromFile(
504076b9443SCy Schubert const char *filename,
505*0197ba46SCy Schubert const char *match,
506*0197ba46SCy Schubert int numdots)
507076b9443SCy Schubert {
508076b9443SCy Schubert static char szBuffer[100];
509076b9443SCy Schubert char *szResult = NULL;
510076b9443SCy Schubert FILE *fp = fopen(filename, "rt");
511076b9443SCy Schubert
512076b9443SCy Schubert if (fp != NULL) {
513076b9443SCy Schubert /*
514076b9443SCy Schubert * Read data until we see our match string.
515076b9443SCy Schubert */
516076b9443SCy Schubert
517*0197ba46SCy Schubert while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
518076b9443SCy Schubert LPSTR p, q;
519076b9443SCy Schubert
520076b9443SCy Schubert p = strstr(szBuffer, match);
521076b9443SCy Schubert if (p != NULL) {
522076b9443SCy Schubert /*
523*0197ba46SCy Schubert * Skip to first digit after the match.
524076b9443SCy Schubert */
525076b9443SCy Schubert
526*0197ba46SCy Schubert p += strlen(match);
527*0197ba46SCy Schubert while (*p && !isdigit((unsigned char)*p)) {
528076b9443SCy Schubert ++p;
529076b9443SCy Schubert }
530076b9443SCy Schubert
531076b9443SCy Schubert /*
532076b9443SCy Schubert * Find ending whitespace.
533076b9443SCy Schubert */
534076b9443SCy Schubert
535076b9443SCy Schubert q = p;
536*0197ba46SCy Schubert while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q)
537*0197ba46SCy Schubert && !strchr("ab", q[-1])) || --numdots))) {
538076b9443SCy Schubert ++q;
539076b9443SCy Schubert }
540076b9443SCy Schubert
541*0197ba46SCy Schubert *q = 0;
542*0197ba46SCy Schubert szResult = p;
543076b9443SCy Schubert break;
544076b9443SCy Schubert }
545076b9443SCy Schubert }
546076b9443SCy Schubert fclose(fp);
547076b9443SCy Schubert }
548076b9443SCy Schubert return szResult;
549076b9443SCy Schubert }
550076b9443SCy Schubert
551076b9443SCy Schubert /*
552076b9443SCy Schubert * List helpers for the SubstituteFile function
553076b9443SCy Schubert */
554076b9443SCy Schubert
555076b9443SCy Schubert typedef struct list_item_t {
556076b9443SCy Schubert struct list_item_t *nextPtr;
557076b9443SCy Schubert char * key;
558076b9443SCy Schubert char * value;
559076b9443SCy Schubert } list_item_t;
560076b9443SCy Schubert
561076b9443SCy Schubert /* insert a list item into the list (list may be null) */
562076b9443SCy Schubert static list_item_t *
list_insert(list_item_t ** listPtrPtr,const char * key,const char * value)563076b9443SCy Schubert list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
564076b9443SCy Schubert {
565*0197ba46SCy Schubert list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t));
566076b9443SCy Schubert if (itemPtr) {
567076b9443SCy Schubert itemPtr->key = strdup(key);
568076b9443SCy Schubert itemPtr->value = strdup(value);
569076b9443SCy Schubert itemPtr->nextPtr = NULL;
570076b9443SCy Schubert
571076b9443SCy Schubert while(*listPtrPtr) {
572076b9443SCy Schubert listPtrPtr = &(*listPtrPtr)->nextPtr;
573076b9443SCy Schubert }
574076b9443SCy Schubert *listPtrPtr = itemPtr;
575076b9443SCy Schubert }
576076b9443SCy Schubert return itemPtr;
577076b9443SCy Schubert }
578076b9443SCy Schubert
579076b9443SCy Schubert static void
list_free(list_item_t ** listPtrPtr)580076b9443SCy Schubert list_free(list_item_t **listPtrPtr)
581076b9443SCy Schubert {
582076b9443SCy Schubert list_item_t *tmpPtr, *listPtr = *listPtrPtr;
583076b9443SCy Schubert while (listPtr) {
584076b9443SCy Schubert tmpPtr = listPtr;
585076b9443SCy Schubert listPtr = listPtr->nextPtr;
586076b9443SCy Schubert free(tmpPtr->key);
587076b9443SCy Schubert free(tmpPtr->value);
588076b9443SCy Schubert free(tmpPtr);
589076b9443SCy Schubert }
590076b9443SCy Schubert }
591076b9443SCy Schubert
592076b9443SCy Schubert /*
593076b9443SCy Schubert * SubstituteFile --
594076b9443SCy Schubert * As windows doesn't provide anything useful like sed and it's unreliable
595076b9443SCy Schubert * to use the tclsh you are building against (consider x-platform builds -
596076b9443SCy Schubert * eg compiling AMD64 target from IX86) we provide a simple substitution
597076b9443SCy Schubert * option here to handle autoconf style substitutions.
598076b9443SCy Schubert * The substitution file is whitespace and line delimited. The file should
599076b9443SCy Schubert * consist of lines matching the regular expression:
600076b9443SCy Schubert * \s*\S+\s+\S*$
601076b9443SCy Schubert *
602076b9443SCy Schubert * Usage is something like:
603076b9443SCy Schubert * nmakehlp -S << $** > $@
604076b9443SCy Schubert * @PACKAGE_NAME@ $(PACKAGE_NAME)
605076b9443SCy Schubert * @PACKAGE_VERSION@ $(PACKAGE_VERSION)
606076b9443SCy Schubert * <<
607076b9443SCy Schubert */
608076b9443SCy Schubert
609076b9443SCy Schubert static int
SubstituteFile(const char * substitutions,const char * filename)610076b9443SCy Schubert SubstituteFile(
611076b9443SCy Schubert const char *substitutions,
612076b9443SCy Schubert const char *filename)
613076b9443SCy Schubert {
614076b9443SCy Schubert static char szBuffer[1024], szCopy[1024];
615076b9443SCy Schubert list_item_t *substPtr = NULL;
616076b9443SCy Schubert FILE *fp, *sp;
617076b9443SCy Schubert
618076b9443SCy Schubert fp = fopen(filename, "rt");
619076b9443SCy Schubert if (fp != NULL) {
620076b9443SCy Schubert
621076b9443SCy Schubert /*
622076b9443SCy Schubert * Build a list of substutitions from the first filename
623076b9443SCy Schubert */
624076b9443SCy Schubert
625076b9443SCy Schubert sp = fopen(substitutions, "rt");
626076b9443SCy Schubert if (sp != NULL) {
627*0197ba46SCy Schubert while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) {
628076b9443SCy Schubert unsigned char *ks, *ke, *vs, *ve;
629076b9443SCy Schubert ks = (unsigned char*)szBuffer;
630076b9443SCy Schubert while (ks && *ks && isspace(*ks)) ++ks;
631076b9443SCy Schubert ke = ks;
632076b9443SCy Schubert while (ke && *ke && !isspace(*ke)) ++ke;
633076b9443SCy Schubert vs = ke;
634076b9443SCy Schubert while (vs && *vs && isspace(*vs)) ++vs;
635076b9443SCy Schubert ve = vs;
636076b9443SCy Schubert while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
637076b9443SCy Schubert *ke = 0, *ve = 0;
638076b9443SCy Schubert list_insert(&substPtr, (char*)ks, (char*)vs);
639076b9443SCy Schubert }
640076b9443SCy Schubert fclose(sp);
641076b9443SCy Schubert }
642076b9443SCy Schubert
643076b9443SCy Schubert /* debug: dump the list */
644*0197ba46SCy Schubert #ifndef NDEBUG
645076b9443SCy Schubert {
646076b9443SCy Schubert int n = 0;
647076b9443SCy Schubert list_item_t *p = NULL;
648076b9443SCy Schubert for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
649076b9443SCy Schubert fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
650076b9443SCy Schubert }
651076b9443SCy Schubert }
652076b9443SCy Schubert #endif
653076b9443SCy Schubert
654076b9443SCy Schubert /*
655076b9443SCy Schubert * Run the substitutions over each line of the input
656076b9443SCy Schubert */
657076b9443SCy Schubert
658*0197ba46SCy Schubert while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
659076b9443SCy Schubert list_item_t *p = NULL;
660076b9443SCy Schubert for (p = substPtr; p != NULL; p = p->nextPtr) {
661076b9443SCy Schubert char *m = strstr(szBuffer, p->key);
662076b9443SCy Schubert if (m) {
663076b9443SCy Schubert char *cp, *op, *sp;
664076b9443SCy Schubert cp = szCopy;
665076b9443SCy Schubert op = szBuffer;
666076b9443SCy Schubert while (op != m) *cp++ = *op++;
667076b9443SCy Schubert sp = p->value;
668076b9443SCy Schubert while (sp && *sp) *cp++ = *sp++;
669076b9443SCy Schubert op += strlen(p->key);
670076b9443SCy Schubert while (*op) *cp++ = *op++;
671076b9443SCy Schubert *cp = 0;
672076b9443SCy Schubert memcpy(szBuffer, szCopy, sizeof(szCopy));
673076b9443SCy Schubert }
674076b9443SCy Schubert }
675*0197ba46SCy Schubert printf("%s", szBuffer);
676076b9443SCy Schubert }
677076b9443SCy Schubert
678076b9443SCy Schubert list_free(&substPtr);
679076b9443SCy Schubert }
680076b9443SCy Schubert fclose(fp);
681076b9443SCy Schubert return 0;
682076b9443SCy Schubert }
683076b9443SCy Schubert
FileExists(LPCTSTR szPath)684*0197ba46SCy Schubert BOOL FileExists(LPCTSTR szPath)
685*0197ba46SCy Schubert {
686*0197ba46SCy Schubert #ifndef INVALID_FILE_ATTRIBUTES
687*0197ba46SCy Schubert #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
688*0197ba46SCy Schubert #endif
689*0197ba46SCy Schubert DWORD pathAttr = GetFileAttributes(szPath);
690*0197ba46SCy Schubert return (pathAttr != INVALID_FILE_ATTRIBUTES &&
691*0197ba46SCy Schubert !(pathAttr & FILE_ATTRIBUTE_DIRECTORY));
692*0197ba46SCy Schubert }
693*0197ba46SCy Schubert
694*0197ba46SCy Schubert
695076b9443SCy Schubert /*
696076b9443SCy Schubert * QualifyPath --
697076b9443SCy Schubert *
698076b9443SCy Schubert * This composes the current working directory with a provided path
699076b9443SCy Schubert * and returns the fully qualified and normalized path.
700076b9443SCy Schubert * Mostly needed to setup paths for testing.
701076b9443SCy Schubert */
702076b9443SCy Schubert
703076b9443SCy Schubert static int
QualifyPath(const char * szPath)704076b9443SCy Schubert QualifyPath(
705076b9443SCy Schubert const char *szPath)
706076b9443SCy Schubert {
707076b9443SCy Schubert char szCwd[MAX_PATH + 1];
708*0197ba46SCy Schubert
709*0197ba46SCy Schubert GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL);
710076b9443SCy Schubert printf("%s\n", szCwd);
711076b9443SCy Schubert return 0;
712076b9443SCy Schubert }
713076b9443SCy Schubert
714076b9443SCy Schubert /*
715*0197ba46SCy Schubert * Implements LocateDependency for a single directory. See that command
716*0197ba46SCy Schubert * for an explanation.
717*0197ba46SCy Schubert * Returns 0 if found after printing the directory.
718*0197ba46SCy Schubert * Returns 1 if not found but no errors.
719*0197ba46SCy Schubert * Returns 2 on any kind of error
720*0197ba46SCy Schubert * Basically, these are used as exit codes for the process.
721*0197ba46SCy Schubert */
LocateDependencyHelper(const char * dir,const char * keypath)722*0197ba46SCy Schubert static int LocateDependencyHelper(const char *dir, const char *keypath)
723*0197ba46SCy Schubert {
724*0197ba46SCy Schubert HANDLE hSearch;
725*0197ba46SCy Schubert char path[MAX_PATH+1];
726*0197ba46SCy Schubert size_t dirlen;
727*0197ba46SCy Schubert int keylen, ret;
728*0197ba46SCy Schubert WIN32_FIND_DATA finfo;
729*0197ba46SCy Schubert
730*0197ba46SCy Schubert if (dir == NULL || keypath == NULL)
731*0197ba46SCy Schubert return 2; /* Have no real error reporting mechanism into nmake */
732*0197ba46SCy Schubert dirlen = strlen(dir);
733*0197ba46SCy Schubert if ((dirlen + 3) > sizeof(path))
734*0197ba46SCy Schubert return 2;
735*0197ba46SCy Schubert strncpy(path, dir, dirlen);
736*0197ba46SCy Schubert strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */
737*0197ba46SCy Schubert keylen = strlen(keypath);
738*0197ba46SCy Schubert
739*0197ba46SCy Schubert #if 0 /* This function is not available in Visual C++ 6 */
740*0197ba46SCy Schubert /*
741*0197ba46SCy Schubert * Use numerics 0 -> FindExInfoStandard,
742*0197ba46SCy Schubert * 1 -> FindExSearchLimitToDirectories,
743*0197ba46SCy Schubert * as these are not defined in Visual C++ 6
744*0197ba46SCy Schubert */
745*0197ba46SCy Schubert hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
746*0197ba46SCy Schubert #else
747*0197ba46SCy Schubert hSearch = FindFirstFile(path, &finfo);
748*0197ba46SCy Schubert #endif
749*0197ba46SCy Schubert if (hSearch == INVALID_HANDLE_VALUE)
750*0197ba46SCy Schubert return 1; /* Not found */
751*0197ba46SCy Schubert
752*0197ba46SCy Schubert /* Loop through all subdirs checking if the keypath is under there */
753*0197ba46SCy Schubert ret = 1; /* Assume not found */
754*0197ba46SCy Schubert do {
755*0197ba46SCy Schubert int sublen;
756*0197ba46SCy Schubert /*
757*0197ba46SCy Schubert * We need to check it is a directory despite the
758*0197ba46SCy Schubert * FindExSearchLimitToDirectories in the above call. See SDK docs
759*0197ba46SCy Schubert */
760*0197ba46SCy Schubert if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
761*0197ba46SCy Schubert continue;
762*0197ba46SCy Schubert sublen = strlen(finfo.cFileName);
763*0197ba46SCy Schubert if ((dirlen+1+sublen+1+keylen+1) > sizeof(path))
764*0197ba46SCy Schubert continue; /* Path does not fit, assume not matched */
765*0197ba46SCy Schubert strncpy(path+dirlen+1, finfo.cFileName, sublen);
766*0197ba46SCy Schubert path[dirlen+1+sublen] = '\\';
767*0197ba46SCy Schubert strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
768*0197ba46SCy Schubert if (FileExists(path)) {
769*0197ba46SCy Schubert /* Found a match, print to stdout */
770*0197ba46SCy Schubert path[dirlen+1+sublen] = '\0';
771*0197ba46SCy Schubert QualifyPath(path);
772*0197ba46SCy Schubert ret = 0;
773*0197ba46SCy Schubert break;
774*0197ba46SCy Schubert }
775*0197ba46SCy Schubert } while (FindNextFile(hSearch, &finfo));
776*0197ba46SCy Schubert FindClose(hSearch);
777*0197ba46SCy Schubert return ret;
778*0197ba46SCy Schubert }
779*0197ba46SCy Schubert
780*0197ba46SCy Schubert /*
781*0197ba46SCy Schubert * LocateDependency --
782*0197ba46SCy Schubert *
783*0197ba46SCy Schubert * Locates a dependency for a package.
784*0197ba46SCy Schubert * keypath - a relative path within the package directory
785*0197ba46SCy Schubert * that is used to confirm it is the correct directory.
786*0197ba46SCy Schubert * The search path for the package directory is currently only
787*0197ba46SCy Schubert * the parent and grandparent of the current working directory.
788*0197ba46SCy Schubert * If found, the command prints
789*0197ba46SCy Schubert * name_DIRPATH=<full path of located directory>
790*0197ba46SCy Schubert * and returns 0. If not found, does not print anything and returns 1.
791*0197ba46SCy Schubert */
LocateDependency(const char * keypath)792*0197ba46SCy Schubert static int LocateDependency(const char *keypath)
793*0197ba46SCy Schubert {
794*0197ba46SCy Schubert size_t i;
795*0197ba46SCy Schubert int ret;
796*0197ba46SCy Schubert static const char *paths[] = {"..", "..\\..", "..\\..\\.."};
797*0197ba46SCy Schubert
798*0197ba46SCy Schubert for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
799*0197ba46SCy Schubert ret = LocateDependencyHelper(paths[i], keypath);
800*0197ba46SCy Schubert if (ret == 0)
801*0197ba46SCy Schubert return ret;
802*0197ba46SCy Schubert }
803*0197ba46SCy Schubert return ret;
804*0197ba46SCy Schubert }
805*0197ba46SCy Schubert
806*0197ba46SCy Schubert
807*0197ba46SCy Schubert /*
808076b9443SCy Schubert * Local variables:
809076b9443SCy Schubert * mode: c
810076b9443SCy Schubert * c-basic-offset: 4
811076b9443SCy Schubert * fill-column: 78
812076b9443SCy Schubert * indent-tabs-mode: t
813076b9443SCy Schubert * tab-width: 8
814076b9443SCy Schubert * End:
815076b9443SCy Schubert */
816