Mercurial > hgrepos > Python2 > PyMuPDF
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 */ |
