comparison mupdf-source/thirdparty/zint/backend_tcl/win/nmakehlp.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*
2 * ----------------------------------------------------------------------------
3 * nmakehlp.c --
4 *
5 * This is used to fix limitations within nmake and the environment.
6 *
7 * Copyright (c) 2002 David Gravereaux.
8 * Copyright (c) 2006 Pat Thoyts
9 *
10 * See the file "license.terms" for information on usage and redistribution of
11 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * ----------------------------------------------------------------------------
13 */
14
15 #define _CRT_SECURE_NO_DEPRECATE
16 #include <windows.h>
17 #ifdef _MSC_VER
18 #pragma comment (lib, "user32.lib")
19 #pragma comment (lib, "kernel32.lib")
20 #endif
21 #include <stdio.h>
22
23 /*
24 * This library is required for x64 builds with _some_ versions of MSVC
25 */
26 #if defined(_M_IA64) || defined(_M_AMD64)
27 #if _MSC_VER >= 1400 && _MSC_VER < 1500
28 #pragma comment(lib, "bufferoverflowU")
29 #endif
30 #endif
31
32 /* ISO hack for dumb VC++ */
33 #if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1900
34 #define snprintf _snprintf
35 #endif
36
37
38 /* protos */
39
40 static int CheckForCompilerFeature(const char *option);
41 static int CheckForLinkerFeature(char **options, int count);
42 static int IsIn(const char *string, const char *substring);
43 static int SubstituteFile(const char *substs, const char *filename);
44 static int QualifyPath(const char *path);
45 static int LocateDependency(const char *keyfile);
46 static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
47 static DWORD WINAPI ReadFromPipe(LPVOID args);
48
49 /* globals */
50
51 #define CHUNK 25
52 #define STATICBUFFERSIZE 1000
53 typedef struct {
54 HANDLE pipe;
55 char buffer[STATICBUFFERSIZE];
56 } pipeinfo;
57
58 pipeinfo Out = {INVALID_HANDLE_VALUE, ""};
59 pipeinfo Err = {INVALID_HANDLE_VALUE, ""};
60
61 /*
62 * exitcodes: 0 == no, 1 == yes, 2 == error
63 */
64
65 int
66 main(
67 int argc,
68 char *argv[])
69 {
70 char msg[300];
71 DWORD dwWritten;
72 int chars;
73 const char *s;
74
75 /*
76 * Make sure children (cl.exe and link.exe) are kept quiet.
77 */
78
79 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
80
81 /*
82 * Make sure the compiler and linker aren't effected by the outside world.
83 */
84
85 SetEnvironmentVariable("CL", "");
86 SetEnvironmentVariable("LINK", "");
87
88 if (argc > 1 && *argv[1] == '-') {
89 switch (*(argv[1]+1)) {
90 case 'c':
91 if (argc != 3) {
92 chars = snprintf(msg, sizeof(msg) - 1,
93 "usage: %s -c <compiler option>\n"
94 "Tests for whether cl.exe supports an option\n"
95 "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
96 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
97 &dwWritten, NULL);
98 return 2;
99 }
100 return CheckForCompilerFeature(argv[2]);
101 case 'l':
102 if (argc < 3) {
103 chars = snprintf(msg, sizeof(msg) - 1,
104 "usage: %s -l <linker option> ?<mandatory option> ...?\n"
105 "Tests for whether link.exe supports an option\n"
106 "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
107 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
108 &dwWritten, NULL);
109 return 2;
110 }
111 return CheckForLinkerFeature(&argv[2], argc-2);
112 case 'f':
113 if (argc == 2) {
114 chars = snprintf(msg, sizeof(msg) - 1,
115 "usage: %s -f <string> <substring>\n"
116 "Find a substring within another\n"
117 "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
118 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
119 &dwWritten, NULL);
120 return 2;
121 } else if (argc == 3) {
122 /*
123 * If the string is blank, there is no match.
124 */
125
126 return 0;
127 } else {
128 return IsIn(argv[2], argv[3]);
129 }
130 case 's':
131 if (argc == 2) {
132 chars = snprintf(msg, sizeof(msg) - 1,
133 "usage: %s -s <substitutions file> <file>\n"
134 "Perform a set of string map type substutitions on a file\n"
135 "exitcodes: 0\n",
136 argv[0]);
137 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
138 &dwWritten, NULL);
139 return 2;
140 }
141 return SubstituteFile(argv[2], argv[3]);
142 case 'V':
143 if (argc != 4) {
144 chars = snprintf(msg, sizeof(msg) - 1,
145 "usage: %s -V filename matchstring\n"
146 "Extract a version from a file:\n"
147 "eg: pkgIndex.tcl \"package ifneeded http\"",
148 argv[0]);
149 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
150 &dwWritten, NULL);
151 return 0;
152 }
153 s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
154 if (s && *s) {
155 printf("%s\n", s);
156 return 0;
157 } else
158 return 1; /* Version not found. Return non-0 exit code */
159
160 case 'Q':
161 if (argc != 3) {
162 chars = snprintf(msg, sizeof(msg) - 1,
163 "usage: %s -Q path\n"
164 "Emit the fully qualified path\n"
165 "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
166 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
167 &dwWritten, NULL);
168 return 2;
169 }
170 return QualifyPath(argv[2]);
171
172 case 'L':
173 if (argc != 3) {
174 chars = snprintf(msg, sizeof(msg) - 1,
175 "usage: %s -L keypath\n"
176 "Emit the fully qualified path of directory containing keypath\n"
177 "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
178 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
179 &dwWritten, NULL);
180 return 2;
181 }
182 return LocateDependency(argv[2]);
183 }
184 }
185 chars = snprintf(msg, sizeof(msg) - 1,
186 "usage: %s -c|-f|-l|-Q|-s|-V ...\n"
187 "This is a little helper app to equalize shell differences between WinNT and\n"
188 "Win9x and get nmake.exe to accomplish its job.\n",
189 argv[0]);
190 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
191 return 2;
192 }
193
194 static int
195 CheckForCompilerFeature(
196 const char *option)
197 {
198 STARTUPINFO si;
199 PROCESS_INFORMATION pi;
200 SECURITY_ATTRIBUTES sa;
201 DWORD threadID;
202 char msg[300];
203 BOOL ok;
204 HANDLE hProcess, h, pipeThreads[2];
205 char cmdline[100];
206
207 hProcess = GetCurrentProcess();
208
209 memset(&pi, 0, sizeof(PROCESS_INFORMATION));
210 memset(&si, 0, sizeof(STARTUPINFO));
211 si.cb = sizeof(STARTUPINFO);
212 si.dwFlags = STARTF_USESTDHANDLES;
213 si.hStdInput = INVALID_HANDLE_VALUE;
214
215 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
216 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
217 sa.lpSecurityDescriptor = NULL;
218 sa.bInheritHandle = FALSE;
219
220 /*
221 * Create a non-inheritable pipe.
222 */
223
224 CreatePipe(&Out.pipe, &h, &sa, 0);
225
226 /*
227 * Dupe the write side, make it inheritable, and close the original.
228 */
229
230 DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
231 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
232
233 /*
234 * Same as above, but for the error side.
235 */
236
237 CreatePipe(&Err.pipe, &h, &sa, 0);
238 DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
239 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
240
241 /*
242 * Base command line.
243 */
244
245 lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");
246
247 /*
248 * Append our option for testing
249 */
250
251 lstrcat(cmdline, option);
252
253 /*
254 * Filename to compile, which exists, but is nothing and empty.
255 */
256
257 lstrcat(cmdline, " .\\nul");
258
259 ok = CreateProcess(
260 NULL, /* Module name. */
261 cmdline, /* Command line. */
262 NULL, /* Process handle not inheritable. */
263 NULL, /* Thread handle not inheritable. */
264 TRUE, /* yes, inherit handles. */
265 DETACHED_PROCESS, /* No console for you. */
266 NULL, /* Use parent's environment block. */
267 NULL, /* Use parent's starting directory. */
268 &si, /* Pointer to STARTUPINFO structure. */
269 &pi); /* Pointer to PROCESS_INFORMATION structure. */
270
271 if (!ok) {
272 DWORD err = GetLastError();
273 int chars = snprintf(msg, sizeof(msg) - 1,
274 "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
275
276 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
277 FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
278 (300-chars), 0);
279 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
280 return 2;
281 }
282
283 /*
284 * Close our references to the write handles that have now been inherited.
285 */
286
287 CloseHandle(si.hStdOutput);
288 CloseHandle(si.hStdError);
289
290 WaitForInputIdle(pi.hProcess, 5000);
291 CloseHandle(pi.hThread);
292
293 /*
294 * Start the pipe reader threads.
295 */
296
297 pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
298 pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
299
300 /*
301 * Block waiting for the process to end.
302 */
303
304 WaitForSingleObject(pi.hProcess, INFINITE);
305 CloseHandle(pi.hProcess);
306
307 /*
308 * Wait for our pipe to get done reading, should it be a little slow.
309 */
310
311 WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
312 CloseHandle(pipeThreads[0]);
313 CloseHandle(pipeThreads[1]);
314
315 /*
316 * Look for the commandline warning code in both streams.
317 * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
318 */
319
320 return !(strstr(Out.buffer, "D4002") != NULL
321 || strstr(Err.buffer, "D4002") != NULL
322 || strstr(Out.buffer, "D9002") != NULL
323 || strstr(Err.buffer, "D9002") != NULL
324 || strstr(Out.buffer, "D2021") != NULL
325 || strstr(Err.buffer, "D2021") != NULL);
326 }
327
328 static int
329 CheckForLinkerFeature(
330 char **options,
331 int count)
332 {
333 STARTUPINFO si;
334 PROCESS_INFORMATION pi;
335 SECURITY_ATTRIBUTES sa;
336 DWORD threadID;
337 char msg[300];
338 BOOL ok;
339 HANDLE hProcess, h, pipeThreads[2];
340 int i;
341 char cmdline[255];
342
343 hProcess = GetCurrentProcess();
344
345 memset(&pi, 0, sizeof(PROCESS_INFORMATION));
346 memset(&si, 0, sizeof(STARTUPINFO));
347 si.cb = sizeof(STARTUPINFO);
348 si.dwFlags = STARTF_USESTDHANDLES;
349 si.hStdInput = INVALID_HANDLE_VALUE;
350
351 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
352 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
353 sa.lpSecurityDescriptor = NULL;
354 sa.bInheritHandle = TRUE;
355
356 /*
357 * Create a non-inheritible pipe.
358 */
359
360 CreatePipe(&Out.pipe, &h, &sa, 0);
361
362 /*
363 * Dupe the write side, make it inheritable, and close the original.
364 */
365
366 DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
367 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
368
369 /*
370 * Same as above, but for the error side.
371 */
372
373 CreatePipe(&Err.pipe, &h, &sa, 0);
374 DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
375 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
376
377 /*
378 * Base command line.
379 */
380
381 lstrcpy(cmdline, "link.exe -nologo ");
382
383 /*
384 * Append our option for testing.
385 */
386
387 for (i = 0; i < count; i++) {
388 lstrcat(cmdline, " \"");
389 lstrcat(cmdline, options[i]);
390 lstrcat(cmdline, "\"");
391 }
392
393 ok = CreateProcess(
394 NULL, /* Module name. */
395 cmdline, /* Command line. */
396 NULL, /* Process handle not inheritable. */
397 NULL, /* Thread handle not inheritable. */
398 TRUE, /* yes, inherit handles. */
399 DETACHED_PROCESS, /* No console for you. */
400 NULL, /* Use parent's environment block. */
401 NULL, /* Use parent's starting directory. */
402 &si, /* Pointer to STARTUPINFO structure. */
403 &pi); /* Pointer to PROCESS_INFORMATION structure. */
404
405 if (!ok) {
406 DWORD err = GetLastError();
407 int chars = snprintf(msg, sizeof(msg) - 1,
408 "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
409
410 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
411 FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
412 (300-chars), 0);
413 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
414 return 2;
415 }
416
417 /*
418 * Close our references to the write handles that have now been inherited.
419 */
420
421 CloseHandle(si.hStdOutput);
422 CloseHandle(si.hStdError);
423
424 WaitForInputIdle(pi.hProcess, 5000);
425 CloseHandle(pi.hThread);
426
427 /*
428 * Start the pipe reader threads.
429 */
430
431 pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
432 pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
433
434 /*
435 * Block waiting for the process to end.
436 */
437
438 WaitForSingleObject(pi.hProcess, INFINITE);
439 CloseHandle(pi.hProcess);
440
441 /*
442 * Wait for our pipe to get done reading, should it be a little slow.
443 */
444
445 WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
446 CloseHandle(pipeThreads[0]);
447 CloseHandle(pipeThreads[1]);
448
449 /*
450 * Look for the commandline warning code in the stderr stream.
451 */
452
453 return !(strstr(Out.buffer, "LNK1117") != NULL ||
454 strstr(Err.buffer, "LNK1117") != NULL ||
455 strstr(Out.buffer, "LNK4044") != NULL ||
456 strstr(Err.buffer, "LNK4044") != NULL ||
457 strstr(Out.buffer, "LNK4224") != NULL ||
458 strstr(Err.buffer, "LNK4224") != NULL);
459 }
460
461 static DWORD WINAPI
462 ReadFromPipe(
463 LPVOID args)
464 {
465 pipeinfo *pi = (pipeinfo *) args;
466 char *lastBuf = pi->buffer;
467 DWORD dwRead;
468 BOOL ok;
469
470 again:
471 if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
472 CloseHandle(pi->pipe);
473 return (DWORD)-1;
474 }
475 ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
476 if (!ok || dwRead == 0) {
477 CloseHandle(pi->pipe);
478 return 0;
479 }
480 lastBuf += dwRead;
481 goto again;
482
483 return 0; /* makes the compiler happy */
484 }
485
486 static int
487 IsIn(
488 const char *string,
489 const char *substring)
490 {
491 return (strstr(string, substring) != NULL);
492 }
493
494 /*
495 * GetVersionFromFile --
496 * Looks for a match string in a file and then returns the version
497 * following the match where a version is anything acceptable to
498 * package provide or package ifneeded.
499 */
500
501 static const char *
502 GetVersionFromFile(
503 const char *filename,
504 const char *match,
505 int numdots)
506 {
507 static char szBuffer[100];
508 char *szResult = NULL;
509 FILE *fp = fopen(filename, "rt");
510
511 if (fp != NULL) {
512 /*
513 * Read data until we see our match string.
514 */
515
516 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
517 LPSTR p, q;
518
519 p = strstr(szBuffer, match);
520 if (p != NULL) {
521 /*
522 * Skip to first digit after the match.
523 */
524
525 p += strlen(match);
526 while (*p && !isdigit((unsigned char)*p)) {
527 ++p;
528 }
529
530 /*
531 * Find ending whitespace.
532 */
533
534 q = p;
535 while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q)
536 && !strchr("ab", q[-1])) || --numdots))) {
537 ++q;
538 }
539
540 *q = 0;
541 szResult = p;
542 break;
543 }
544 }
545 fclose(fp);
546 }
547 return szResult;
548 }
549
550 /*
551 * List helpers for the SubstituteFile function
552 */
553
554 typedef struct list_item_t {
555 struct list_item_t *nextPtr;
556 char * key;
557 char * value;
558 } list_item_t;
559
560 /* insert a list item into the list (list may be null) */
561 static list_item_t *
562 list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
563 {
564 list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t));
565 if (itemPtr) {
566 itemPtr->key = strdup(key);
567 itemPtr->value = strdup(value);
568 itemPtr->nextPtr = NULL;
569
570 while(*listPtrPtr) {
571 listPtrPtr = &(*listPtrPtr)->nextPtr;
572 }
573 *listPtrPtr = itemPtr;
574 }
575 return itemPtr;
576 }
577
578 static void
579 list_free(list_item_t **listPtrPtr)
580 {
581 list_item_t *tmpPtr, *listPtr = *listPtrPtr;
582 while (listPtr) {
583 tmpPtr = listPtr;
584 listPtr = listPtr->nextPtr;
585 free(tmpPtr->key);
586 free(tmpPtr->value);
587 free(tmpPtr);
588 }
589 }
590
591 /*
592 * SubstituteFile --
593 * As windows doesn't provide anything useful like sed and it's unreliable
594 * to use the tclsh you are building against (consider x-platform builds -
595 * e.g. compiling AMD64 target from IX86) we provide a simple substitution
596 * option here to handle autoconf style substitutions.
597 * The substitution file is whitespace and line delimited. The file should
598 * consist of lines matching the regular expression:
599 * \s*\S+\s+\S*$
600 *
601 * Usage is something like:
602 * nmakehlp -S << $** > $@
603 * @PACKAGE_NAME@ $(PACKAGE_NAME)
604 * @PACKAGE_VERSION@ $(PACKAGE_VERSION)
605 * <<
606 */
607
608 static int
609 SubstituteFile(
610 const char *substitutions,
611 const char *filename)
612 {
613 static char szBuffer[1024], szCopy[1024];
614 list_item_t *substPtr = NULL;
615 FILE *fp, *sp;
616
617 fp = fopen(filename, "rt");
618 if (fp != NULL) {
619
620 /*
621 * Build a list of substitutions from the first filename
622 */
623
624 sp = fopen(substitutions, "rt");
625 if (sp != NULL) {
626 while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) {
627 unsigned char *ks, *ke, *vs, *ve;
628 ks = (unsigned char*)szBuffer;
629 while (ks && *ks && isspace(*ks)) ++ks;
630 ke = ks;
631 while (ke && *ke && !isspace(*ke)) ++ke;
632 vs = ke;
633 while (vs && *vs && isspace(*vs)) ++vs;
634 ve = vs;
635 while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
636 *ke = 0, *ve = 0;
637 list_insert(&substPtr, (char*)ks, (char*)vs);
638 }
639 fclose(sp);
640 }
641
642 /* debug: dump the list */
643 #ifndef NDEBUG
644 {
645 int n = 0;
646 list_item_t *p = NULL;
647 for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
648 fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
649 }
650 }
651 #endif
652
653 /*
654 * Run the substitutions over each line of the input
655 */
656
657 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
658 list_item_t *p = NULL;
659 for (p = substPtr; p != NULL; p = p->nextPtr) {
660 char *m = strstr(szBuffer, p->key);
661 if (m) {
662 char *cp, *op, *sp;
663 cp = szCopy;
664 op = szBuffer;
665 while (op != m) *cp++ = *op++;
666 sp = p->value;
667 while (sp && *sp) *cp++ = *sp++;
668 op += strlen(p->key);
669 while (*op) *cp++ = *op++;
670 *cp = 0;
671 memcpy(szBuffer, szCopy, sizeof(szCopy));
672 }
673 }
674 printf("%s", szBuffer);
675 }
676
677 list_free(&substPtr);
678 }
679 fclose(fp);
680 return 0;
681 }
682
683 BOOL FileExists(LPCTSTR szPath)
684 {
685 #ifndef INVALID_FILE_ATTRIBUTES
686 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
687 #endif
688 DWORD pathAttr = GetFileAttributes(szPath);
689 return (pathAttr != INVALID_FILE_ATTRIBUTES &&
690 !(pathAttr & FILE_ATTRIBUTE_DIRECTORY));
691 }
692
693
694 /*
695 * QualifyPath --
696 *
697 * This composes the current working directory with a provided path
698 * and returns the fully qualified and normalized path.
699 * Mostly needed to setup paths for testing.
700 */
701
702 static int
703 QualifyPath(
704 const char *szPath)
705 {
706 char szCwd[MAX_PATH + 1];
707
708 GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL);
709 printf("%s\n", szCwd);
710 return 0;
711 }
712
713 /*
714 * Implements LocateDependency for a single directory. See that command
715 * for an explanation.
716 * Returns 0 if found after printing the directory.
717 * Returns 1 if not found but no errors.
718 * Returns 2 on any kind of error
719 * Basically, these are used as exit codes for the process.
720 */
721 static int LocateDependencyHelper(const char *dir, const char *keypath)
722 {
723 HANDLE hSearch;
724 char path[MAX_PATH+1];
725 size_t dirlen;
726 int keylen, ret;
727 WIN32_FIND_DATA finfo;
728
729 if (dir == NULL || keypath == NULL) {
730 return 2; /* Have no real error reporting mechanism into nmake */
731 }
732 dirlen = strlen(dir);
733 if (dirlen > sizeof(path) - 3) {
734 return 2;
735 }
736 strncpy(path, dir, dirlen);
737 strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */
738 keylen = strlen(keypath);
739
740 #if 0 /* This function is not available in Visual C++ 6 */
741 /*
742 * Use numerics 0 -> FindExInfoStandard,
743 * 1 -> FindExSearchLimitToDirectories,
744 * as these are not defined in Visual C++ 6
745 */
746 hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
747 #else
748 hSearch = FindFirstFile(path, &finfo);
749 #endif
750 if (hSearch == INVALID_HANDLE_VALUE) {
751 return 1; /* Not found */
752 }
753
754 /* Loop through all subdirs checking if the keypath is under there */
755 ret = 1; /* Assume not found */
756 do {
757 int sublen;
758 /*
759 * We need to check it is a directory despite the
760 * FindExSearchLimitToDirectories in the above call. See SDK docs
761 */
762 if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
763 continue;
764 }
765 sublen = strlen(finfo.cFileName);
766 if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) {
767 continue; /* Path does not fit, assume not matched */
768 }
769 strncpy(path+dirlen+1, finfo.cFileName, sublen);
770 path[dirlen+1+sublen] = '\\';
771 strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
772 if (FileExists(path)) {
773 /* Found a match, print to stdout */
774 path[dirlen+1+sublen] = '\0';
775 QualifyPath(path);
776 ret = 0;
777 break;
778 }
779 } while (FindNextFile(hSearch, &finfo));
780 FindClose(hSearch);
781 return ret;
782 }
783
784 /*
785 * LocateDependency --
786 *
787 * Locates a dependency for a package.
788 * keypath - a relative path within the package directory
789 * that is used to confirm it is the correct directory.
790 * The search path for the package directory is currently only
791 * the parent and grandparent of the current working directory.
792 * If found, the command prints
793 * name_DIRPATH=<full path of located directory>
794 * and returns 0. If not found, does not print anything and returns 1.
795 */
796 static int LocateDependency(const char *keypath)
797 {
798 size_t i;
799 int ret;
800 static const char *paths[] = {"..", "..\\..", "..\\..\\.."};
801
802 for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
803 ret = LocateDependencyHelper(paths[i], keypath);
804 if (ret == 0) {
805 return ret;
806 }
807 }
808 return ret;
809 }
810
811
812 /*
813 * Local variables:
814 * mode: c
815 * c-basic-offset: 4
816 * fill-column: 78
817 * indent-tabs-mode: t
818 * tab-width: 8
819 * End:
820 */