xref: /freebsd/contrib/sqlite3/tea/win/nmakehlp.c (revision 0197ba46)
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