| 1 | /* | 
|---|
| 2 |  * ---------------------------------------------------------------------------- | 
|---|
| 3 |  * nmakehlp.c -- | 
|---|
| 4 |  * | 
|---|
| 5 |  *      This is used to fix limitations within nmake and the environment. | 
|---|
| 6 |  * | 
|---|
| 7 |  * Copyright (c) 2002 by David Gravereaux. | 
|---|
| 8 |  * Copyright (c) 2006 by 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 |  * RCS: @(#) $Id: nmakehlp.c,v 1.21 2007/12/14 02:27:11 patthoyts Exp $ | 
|---|
| 15 |  * ---------------------------------------------------------------------------- | 
|---|
| 16 |  */ | 
|---|
| 17 |  | 
|---|
| 18 | #define _CRT_SECURE_NO_DEPRECATE | 
|---|
| 19 | #include <windows.h> | 
|---|
| 20 | #pragma comment (lib, "user32.lib") | 
|---|
| 21 | #pragma comment (lib, "kernel32.lib") | 
|---|
| 22 | #include <stdio.h> | 
|---|
| 23 | #include <math.h> | 
|---|
| 24 |  | 
|---|
| 25 | /* | 
|---|
| 26 |  * This library is required for x64 builds with _some_ versions | 
|---|
| 27 |  */ | 
|---|
| 28 | #if defined(_M_IA64) || defined(_M_AMD64) | 
|---|
| 29 | #if _MSC_FULL_VER > 140000000 && _MSC_FULL_VER <= 140040310 | 
|---|
| 30 | #pragma comment(lib, "bufferoverflowU") | 
|---|
| 31 | #endif | 
|---|
| 32 | #endif | 
|---|
| 33 |  | 
|---|
| 34 | /* ISO hack for dumb VC++ */ | 
|---|
| 35 | #ifdef _MSC_VER | 
|---|
| 36 | #define   snprintf      _snprintf | 
|---|
| 37 | #endif | 
|---|
| 38 |  | 
|---|
| 39 |  | 
|---|
| 40 |  | 
|---|
| 41 | /* protos */ | 
|---|
| 42 |  | 
|---|
| 43 | int             CheckForCompilerFeature(const char *option); | 
|---|
| 44 | int             CheckForLinkerFeature(const char *option); | 
|---|
| 45 | int             IsIn(const char *string, const char *substring); | 
|---|
| 46 | int             GrepForDefine(const char *file, const char *string); | 
|---|
| 47 | int             SubstituteFile(const char *substs, const char *filename); | 
|---|
| 48 | const char *    GetVersionFromFile(const char *filename, const char *match); | 
|---|
| 49 | DWORD WINAPI    ReadFromPipe(LPVOID args); | 
|---|
| 50 |  | 
|---|
| 51 | /* globals */ | 
|---|
| 52 |  | 
|---|
| 53 | #define CHUNK   25 | 
|---|
| 54 | #define STATICBUFFERSIZE    1000 | 
|---|
| 55 | typedef struct { | 
|---|
| 56 |     HANDLE pipe; | 
|---|
| 57 |     char buffer[STATICBUFFERSIZE]; | 
|---|
| 58 | } pipeinfo; | 
|---|
| 59 |  | 
|---|
| 60 | pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; | 
|---|
| 61 | pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; | 
|---|
| 62 |  | 
|---|
| 63 | /* | 
|---|
| 64 |  * exitcodes: 0 == no, 1 == yes, 2 == error | 
|---|
| 65 |  */ | 
|---|
| 66 |  | 
|---|
| 67 | int | 
|---|
| 68 | main( | 
|---|
| 69 |     int argc, | 
|---|
| 70 |     char *argv[]) | 
|---|
| 71 | { | 
|---|
| 72 |     char msg[300]; | 
|---|
| 73 |     DWORD dwWritten; | 
|---|
| 74 |     int chars; | 
|---|
| 75 |  | 
|---|
| 76 |     /* | 
|---|
| 77 |      * Make sure children (cl.exe and link.exe) are kept quiet. | 
|---|
| 78 |      */ | 
|---|
| 79 |  | 
|---|
| 80 |     SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); | 
|---|
| 81 |  | 
|---|
| 82 |     /* | 
|---|
| 83 |      * Make sure the compiler and linker aren't effected by the outside world. | 
|---|
| 84 |      */ | 
|---|
| 85 |  | 
|---|
| 86 |     SetEnvironmentVariable("CL", ""); | 
|---|
| 87 |     SetEnvironmentVariable("LINK", ""); | 
|---|
| 88 |  | 
|---|
| 89 |     if (argc > 1 && *argv[1] == '-') { | 
|---|
| 90 |         switch (*(argv[1]+1)) { | 
|---|
| 91 |         case 'c': | 
|---|
| 92 |             if (argc != 3) { | 
|---|
| 93 |                 chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 94 |                         "usage: %s -c <compiler option>\n" | 
|---|
| 95 |                         "Tests for whether cl.exe supports an option\n" | 
|---|
| 96 |                         "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); | 
|---|
| 97 |                 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, | 
|---|
| 98 |                         &dwWritten, NULL); | 
|---|
| 99 |                 return 2; | 
|---|
| 100 |             } | 
|---|
| 101 |             return CheckForCompilerFeature(argv[2]); | 
|---|
| 102 |         case 'l': | 
|---|
| 103 |             if (argc != 3) { | 
|---|
| 104 |                 chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 105 |                         "usage: %s -l <linker option>\n" | 
|---|
| 106 |                         "Tests for whether link.exe supports an option\n" | 
|---|
| 107 |                         "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); | 
|---|
| 108 |                 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, | 
|---|
| 109 |                         &dwWritten, NULL); | 
|---|
| 110 |                 return 2; | 
|---|
| 111 |             } | 
|---|
| 112 |             return CheckForLinkerFeature(argv[2]); | 
|---|
| 113 |         case 'f': | 
|---|
| 114 |             if (argc == 2) { | 
|---|
| 115 |                 chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 116 |                         "usage: %s -f <string> <substring>\n" | 
|---|
| 117 |                         "Find a substring within another\n" | 
|---|
| 118 |                         "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); | 
|---|
| 119 |                 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, | 
|---|
| 120 |                         &dwWritten, NULL); | 
|---|
| 121 |                 return 2; | 
|---|
| 122 |             } else if (argc == 3) { | 
|---|
| 123 |                 /* | 
|---|
| 124 |                  * If the string is blank, there is no match. | 
|---|
| 125 |                  */ | 
|---|
| 126 |  | 
|---|
| 127 |                 return 0; | 
|---|
| 128 |             } else { | 
|---|
| 129 |                 return IsIn(argv[2], argv[3]); | 
|---|
| 130 |             } | 
|---|
| 131 |         case 'g': | 
|---|
| 132 |             if (argc == 2) { | 
|---|
| 133 |                 chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 134 |                         "usage: %s -g <file> <string>\n" | 
|---|
| 135 |                         "grep for a #define\n" | 
|---|
| 136 |                         "exitcodes: integer of the found string (no decimals)\n", | 
|---|
| 137 |                         argv[0]); | 
|---|
| 138 |                 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, | 
|---|
| 139 |                         &dwWritten, NULL); | 
|---|
| 140 |                 return 2; | 
|---|
| 141 |             } | 
|---|
| 142 |             return GrepForDefine(argv[2], argv[3]); | 
|---|
| 143 |         case 's': | 
|---|
| 144 |             if (argc == 2) { | 
|---|
| 145 |                 chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 146 |                         "usage: %s -s <substitutions file> <file>\n" | 
|---|
| 147 |                         "Perform a set of string map type substutitions on a file\n" | 
|---|
| 148 |                         "exitcodes: 0\n", | 
|---|
| 149 |                         argv[0]); | 
|---|
| 150 |                 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, | 
|---|
| 151 |                         &dwWritten, NULL); | 
|---|
| 152 |                 return 2; | 
|---|
| 153 |             } | 
|---|
| 154 |             return SubstituteFile(argv[2], argv[3]); | 
|---|
| 155 |         case 'V': | 
|---|
| 156 |             if (argc != 4) { | 
|---|
| 157 |                 chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 158 |                     "usage: %s -V filename matchstring\n" | 
|---|
| 159 |                     "Extract a version from a file:\n" | 
|---|
| 160 |                     "eg: pkgIndex.tcl \"package ifneeded http\"", | 
|---|
| 161 |                     argv[0]); | 
|---|
| 162 |                 WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, | 
|---|
| 163 |                     &dwWritten, NULL); | 
|---|
| 164 |                 return 0; | 
|---|
| 165 |             } | 
|---|
| 166 |             printf("%s\n", GetVersionFromFile(argv[2], argv[3])); | 
|---|
| 167 |             return 0; | 
|---|
| 168 |         } | 
|---|
| 169 |     } | 
|---|
| 170 |     chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 171 |             "usage: %s -c|-l|-f|-g|-V ...\n" | 
|---|
| 172 |             "This is a little helper app to equalize shell differences between WinNT and\n" | 
|---|
| 173 |             "Win9x and get nmake.exe to accomplish its job.\n", | 
|---|
| 174 |             argv[0]); | 
|---|
| 175 |     WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); | 
|---|
| 176 |     return 2; | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | int | 
|---|
| 180 | CheckForCompilerFeature( | 
|---|
| 181 |     const char *option) | 
|---|
| 182 | { | 
|---|
| 183 |     STARTUPINFO si; | 
|---|
| 184 |     PROCESS_INFORMATION pi; | 
|---|
| 185 |     SECURITY_ATTRIBUTES sa; | 
|---|
| 186 |     DWORD threadID; | 
|---|
| 187 |     char msg[300]; | 
|---|
| 188 |     BOOL ok; | 
|---|
| 189 |     HANDLE hProcess, h, pipeThreads[2]; | 
|---|
| 190 |     char cmdline[100]; | 
|---|
| 191 |  | 
|---|
| 192 |     hProcess = GetCurrentProcess(); | 
|---|
| 193 |  | 
|---|
| 194 |     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); | 
|---|
| 195 |     ZeroMemory(&si, sizeof(STARTUPINFO)); | 
|---|
| 196 |     si.cb = sizeof(STARTUPINFO); | 
|---|
| 197 |     si.dwFlags   = STARTF_USESTDHANDLES; | 
|---|
| 198 |     si.hStdInput = INVALID_HANDLE_VALUE; | 
|---|
| 199 |  | 
|---|
| 200 |     ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); | 
|---|
| 201 |     sa.nLength = sizeof(SECURITY_ATTRIBUTES); | 
|---|
| 202 |     sa.lpSecurityDescriptor = NULL; | 
|---|
| 203 |     sa.bInheritHandle = FALSE; | 
|---|
| 204 |  | 
|---|
| 205 |     /* | 
|---|
| 206 |      * Create a non-inheritible pipe. | 
|---|
| 207 |      */ | 
|---|
| 208 |  | 
|---|
| 209 |     CreatePipe(&Out.pipe, &h, &sa, 0); | 
|---|
| 210 |  | 
|---|
| 211 |     /* | 
|---|
| 212 |      * Dupe the write side, make it inheritible, and close the original. | 
|---|
| 213 |      */ | 
|---|
| 214 |  | 
|---|
| 215 |     DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, | 
|---|
| 216 |             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); | 
|---|
| 217 |  | 
|---|
| 218 |     /* | 
|---|
| 219 |      * Same as above, but for the error side. | 
|---|
| 220 |      */ | 
|---|
| 221 |  | 
|---|
| 222 |     CreatePipe(&Err.pipe, &h, &sa, 0); | 
|---|
| 223 |     DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, | 
|---|
| 224 |             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); | 
|---|
| 225 |  | 
|---|
| 226 |     /* | 
|---|
| 227 |      * Base command line. | 
|---|
| 228 |      */ | 
|---|
| 229 |  | 
|---|
| 230 |     lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); | 
|---|
| 231 |  | 
|---|
| 232 |     /* | 
|---|
| 233 |      * Append our option for testing | 
|---|
| 234 |      */ | 
|---|
| 235 |  | 
|---|
| 236 |     lstrcat(cmdline, option); | 
|---|
| 237 |  | 
|---|
| 238 |     /* | 
|---|
| 239 |      * Filename to compile, which exists, but is nothing and empty. | 
|---|
| 240 |      */ | 
|---|
| 241 |  | 
|---|
| 242 |     lstrcat(cmdline, " .\\nul"); | 
|---|
| 243 |  | 
|---|
| 244 |     ok = CreateProcess( | 
|---|
| 245 |             NULL,           /* Module name. */ | 
|---|
| 246 |             cmdline,        /* Command line. */ | 
|---|
| 247 |             NULL,           /* Process handle not inheritable. */ | 
|---|
| 248 |             NULL,           /* Thread handle not inheritable. */ | 
|---|
| 249 |             TRUE,           /* yes, inherit handles. */ | 
|---|
| 250 |             DETACHED_PROCESS, /* No console for you. */ | 
|---|
| 251 |             NULL,           /* Use parent's environment block. */ | 
|---|
| 252 |             NULL,           /* Use parent's starting directory. */ | 
|---|
| 253 |             &si,            /* Pointer to STARTUPINFO structure. */ | 
|---|
| 254 |             &pi);           /* Pointer to PROCESS_INFORMATION structure. */ | 
|---|
| 255 |  | 
|---|
| 256 |     if (!ok) { | 
|---|
| 257 |         DWORD err = GetLastError(); | 
|---|
| 258 |         int chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 259 |                 "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); | 
|---|
| 260 |  | 
|---|
| 261 |         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| | 
|---|
| 262 |                 FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], | 
|---|
| 263 |                 (300-chars), 0); | 
|---|
| 264 |         WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg,lstrlen(msg), &err,NULL); | 
|---|
| 265 |         return 2; | 
|---|
| 266 |     } | 
|---|
| 267 |  | 
|---|
| 268 |     /* | 
|---|
| 269 |      * Close our references to the write handles that have now been inherited. | 
|---|
| 270 |      */ | 
|---|
| 271 |  | 
|---|
| 272 |     CloseHandle(si.hStdOutput); | 
|---|
| 273 |     CloseHandle(si.hStdError); | 
|---|
| 274 |  | 
|---|
| 275 |     WaitForInputIdle(pi.hProcess, 5000); | 
|---|
| 276 |     CloseHandle(pi.hThread); | 
|---|
| 277 |  | 
|---|
| 278 |     /* | 
|---|
| 279 |      * Start the pipe reader threads. | 
|---|
| 280 |      */ | 
|---|
| 281 |  | 
|---|
| 282 |     pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); | 
|---|
| 283 |     pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); | 
|---|
| 284 |  | 
|---|
| 285 |     /* | 
|---|
| 286 |      * Block waiting for the process to end. | 
|---|
| 287 |      */ | 
|---|
| 288 |  | 
|---|
| 289 |     WaitForSingleObject(pi.hProcess, INFINITE); | 
|---|
| 290 |     CloseHandle(pi.hProcess); | 
|---|
| 291 |  | 
|---|
| 292 |     /* | 
|---|
| 293 |      * Wait for our pipe to get done reading, should it be a little slow. | 
|---|
| 294 |      */ | 
|---|
| 295 |  | 
|---|
| 296 |     WaitForMultipleObjects(2, pipeThreads, TRUE, 500); | 
|---|
| 297 |     CloseHandle(pipeThreads[0]); | 
|---|
| 298 |     CloseHandle(pipeThreads[1]); | 
|---|
| 299 |  | 
|---|
| 300 |     /* | 
|---|
| 301 |      * Look for the commandline warning code in both streams. | 
|---|
| 302 |      *  - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. | 
|---|
| 303 |      */ | 
|---|
| 304 |  | 
|---|
| 305 |     return !(strstr(Out.buffer, "D4002") != NULL | 
|---|
| 306 |              || strstr(Err.buffer, "D4002") != NULL | 
|---|
| 307 |              || strstr(Out.buffer, "D9002") != NULL | 
|---|
| 308 |              || strstr(Err.buffer, "D9002") != NULL | 
|---|
| 309 |              || strstr(Out.buffer, "D2021") != NULL | 
|---|
| 310 |              || strstr(Err.buffer, "D2021") != NULL); | 
|---|
| 311 | } | 
|---|
| 312 |  | 
|---|
| 313 | int | 
|---|
| 314 | CheckForLinkerFeature( | 
|---|
| 315 |     const char *option) | 
|---|
| 316 | { | 
|---|
| 317 |     STARTUPINFO si; | 
|---|
| 318 |     PROCESS_INFORMATION pi; | 
|---|
| 319 |     SECURITY_ATTRIBUTES sa; | 
|---|
| 320 |     DWORD threadID; | 
|---|
| 321 |     char msg[300]; | 
|---|
| 322 |     BOOL ok; | 
|---|
| 323 |     HANDLE hProcess, h, pipeThreads[2]; | 
|---|
| 324 |     char cmdline[100]; | 
|---|
| 325 |  | 
|---|
| 326 |     hProcess = GetCurrentProcess(); | 
|---|
| 327 |  | 
|---|
| 328 |     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); | 
|---|
| 329 |     ZeroMemory(&si, sizeof(STARTUPINFO)); | 
|---|
| 330 |     si.cb = sizeof(STARTUPINFO); | 
|---|
| 331 |     si.dwFlags   = STARTF_USESTDHANDLES; | 
|---|
| 332 |     si.hStdInput = INVALID_HANDLE_VALUE; | 
|---|
| 333 |  | 
|---|
| 334 |     ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); | 
|---|
| 335 |     sa.nLength = sizeof(SECURITY_ATTRIBUTES); | 
|---|
| 336 |     sa.lpSecurityDescriptor = NULL; | 
|---|
| 337 |     sa.bInheritHandle = TRUE; | 
|---|
| 338 |  | 
|---|
| 339 |     /* | 
|---|
| 340 |      * Create a non-inheritible pipe. | 
|---|
| 341 |      */ | 
|---|
| 342 |  | 
|---|
| 343 |     CreatePipe(&Out.pipe, &h, &sa, 0); | 
|---|
| 344 |  | 
|---|
| 345 |     /* | 
|---|
| 346 |      * Dupe the write side, make it inheritible, and close the original. | 
|---|
| 347 |      */ | 
|---|
| 348 |  | 
|---|
| 349 |     DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, | 
|---|
| 350 |             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); | 
|---|
| 351 |  | 
|---|
| 352 |     /* | 
|---|
| 353 |      * Same as above, but for the error side. | 
|---|
| 354 |      */ | 
|---|
| 355 |  | 
|---|
| 356 |     CreatePipe(&Err.pipe, &h, &sa, 0); | 
|---|
| 357 |     DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, | 
|---|
| 358 |             DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); | 
|---|
| 359 |  | 
|---|
| 360 |     /* | 
|---|
| 361 |      * Base command line. | 
|---|
| 362 |      */ | 
|---|
| 363 |  | 
|---|
| 364 |     lstrcpy(cmdline, "link.exe -nologo "); | 
|---|
| 365 |  | 
|---|
| 366 |     /* | 
|---|
| 367 |      * Append our option for testing. | 
|---|
| 368 |      */ | 
|---|
| 369 |  | 
|---|
| 370 |     lstrcat(cmdline, option); | 
|---|
| 371 |  | 
|---|
| 372 |     ok = CreateProcess( | 
|---|
| 373 |             NULL,           /* Module name. */ | 
|---|
| 374 |             cmdline,        /* Command line. */ | 
|---|
| 375 |             NULL,           /* Process handle not inheritable. */ | 
|---|
| 376 |             NULL,           /* Thread handle not inheritable. */ | 
|---|
| 377 |             TRUE,           /* yes, inherit handles. */ | 
|---|
| 378 |             DETACHED_PROCESS, /* No console for you. */ | 
|---|
| 379 |             NULL,           /* Use parent's environment block. */ | 
|---|
| 380 |             NULL,           /* Use parent's starting directory. */ | 
|---|
| 381 |             &si,            /* Pointer to STARTUPINFO structure. */ | 
|---|
| 382 |             &pi);           /* Pointer to PROCESS_INFORMATION structure. */ | 
|---|
| 383 |  | 
|---|
| 384 |     if (!ok) { | 
|---|
| 385 |         DWORD err = GetLastError(); | 
|---|
| 386 |         int chars = snprintf(msg, sizeof(msg) - 1, | 
|---|
| 387 |                 "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); | 
|---|
| 388 |  | 
|---|
| 389 |         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| | 
|---|
| 390 |                 FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], | 
|---|
| 391 |                 (300-chars), 0); | 
|---|
| 392 |         WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg,lstrlen(msg), &err,NULL); | 
|---|
| 393 |         return 2; | 
|---|
| 394 |     } | 
|---|
| 395 |  | 
|---|
| 396 |     /* | 
|---|
| 397 |      * Close our references to the write handles that have now been inherited. | 
|---|
| 398 |      */ | 
|---|
| 399 |  | 
|---|
| 400 |     CloseHandle(si.hStdOutput); | 
|---|
| 401 |     CloseHandle(si.hStdError); | 
|---|
| 402 |  | 
|---|
| 403 |     WaitForInputIdle(pi.hProcess, 5000); | 
|---|
| 404 |     CloseHandle(pi.hThread); | 
|---|
| 405 |  | 
|---|
| 406 |     /* | 
|---|
| 407 |      * Start the pipe reader threads. | 
|---|
| 408 |      */ | 
|---|
| 409 |  | 
|---|
| 410 |     pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); | 
|---|
| 411 |     pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); | 
|---|
| 412 |  | 
|---|
| 413 |     /* | 
|---|
| 414 |      * Block waiting for the process to end. | 
|---|
| 415 |      */ | 
|---|
| 416 |  | 
|---|
| 417 |     WaitForSingleObject(pi.hProcess, INFINITE); | 
|---|
| 418 |     CloseHandle(pi.hProcess); | 
|---|
| 419 |  | 
|---|
| 420 |     /* | 
|---|
| 421 |      * Wait for our pipe to get done reading, should it be a little slow. | 
|---|
| 422 |      */ | 
|---|
| 423 |  | 
|---|
| 424 |     WaitForMultipleObjects(2, pipeThreads, TRUE, 500); | 
|---|
| 425 |     CloseHandle(pipeThreads[0]); | 
|---|
| 426 |     CloseHandle(pipeThreads[1]); | 
|---|
| 427 |  | 
|---|
| 428 |     /* | 
|---|
| 429 |      * Look for the commandline warning code in the stderr stream. | 
|---|
| 430 |      */ | 
|---|
| 431 |  | 
|---|
| 432 |     return !(strstr(Out.buffer, "LNK1117") != NULL || | 
|---|
| 433 |             strstr(Err.buffer, "LNK1117") != NULL || | 
|---|
| 434 |             strstr(Out.buffer, "LNK4044") != NULL || | 
|---|
| 435 |             strstr(Err.buffer, "LNK4044") != NULL); | 
|---|
| 436 | } | 
|---|
| 437 |  | 
|---|
| 438 | DWORD WINAPI | 
|---|
| 439 | ReadFromPipe( | 
|---|
| 440 |     LPVOID args) | 
|---|
| 441 | { | 
|---|
| 442 |     pipeinfo *pi = (pipeinfo *) args; | 
|---|
| 443 |     char *lastBuf = pi->buffer; | 
|---|
| 444 |     DWORD dwRead; | 
|---|
| 445 |     BOOL ok; | 
|---|
| 446 |  | 
|---|
| 447 |   again: | 
|---|
| 448 |     if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { | 
|---|
| 449 |         CloseHandle(pi->pipe); | 
|---|
| 450 |         return (DWORD)-1; | 
|---|
| 451 |     } | 
|---|
| 452 |     ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); | 
|---|
| 453 |     if (!ok || dwRead == 0) { | 
|---|
| 454 |         CloseHandle(pi->pipe); | 
|---|
| 455 |         return 0; | 
|---|
| 456 |     } | 
|---|
| 457 |     lastBuf += dwRead; | 
|---|
| 458 |     goto again; | 
|---|
| 459 |  | 
|---|
| 460 |     return 0;  /* makes the compiler happy */ | 
|---|
| 461 | } | 
|---|
| 462 |  | 
|---|
| 463 | int | 
|---|
| 464 | IsIn( | 
|---|
| 465 |     const char *string, | 
|---|
| 466 |     const char *substring) | 
|---|
| 467 | { | 
|---|
| 468 |     return (strstr(string, substring) != NULL); | 
|---|
| 469 | } | 
|---|
| 470 |  | 
|---|
| 471 | /* | 
|---|
| 472 |  * Find a specified #define by name. | 
|---|
| 473 |  * | 
|---|
| 474 |  * If the line is '#define TCL_VERSION "8.5"', it returns 85 as the result. | 
|---|
| 475 |  */ | 
|---|
| 476 |  | 
|---|
| 477 | int | 
|---|
| 478 | GrepForDefine( | 
|---|
| 479 |     const char *file, | 
|---|
| 480 |     const char *string) | 
|---|
| 481 | { | 
|---|
| 482 |     char s1[51], s2[51], s3[51]; | 
|---|
| 483 |     FILE *f = fopen(file, "rt"); | 
|---|
| 484 |  | 
|---|
| 485 |     if (f == NULL) { | 
|---|
| 486 |         return 0; | 
|---|
| 487 |     } | 
|---|
| 488 |  | 
|---|
| 489 |     do { | 
|---|
| 490 |         int r = fscanf(f, "%50s", s1); | 
|---|
| 491 |  | 
|---|
| 492 |         if (r == 1 && !strcmp(s1, "#define")) { | 
|---|
| 493 |             /* | 
|---|
| 494 |              * Get next two words. | 
|---|
| 495 |              */ | 
|---|
| 496 |  | 
|---|
| 497 |             r = fscanf(f, "%50s %50s", s2, s3); | 
|---|
| 498 |             if (r != 2) { | 
|---|
| 499 |                 continue; | 
|---|
| 500 |             } | 
|---|
| 501 |  | 
|---|
| 502 |             /* | 
|---|
| 503 |              * Is the first word what we're looking for? | 
|---|
| 504 |              */ | 
|---|
| 505 |  | 
|---|
| 506 |             if (!strcmp(s2, string)) { | 
|---|
| 507 |                 double d1; | 
|---|
| 508 |  | 
|---|
| 509 |                 fclose(f); | 
|---|
| 510 |  | 
|---|
| 511 |                 /* | 
|---|
| 512 |                  * Add 1 past first double quote char. "8.5" | 
|---|
| 513 |                  */ | 
|---|
| 514 |  | 
|---|
| 515 |                 d1 = atof(s3 + 1);                /*    8.5  */ | 
|---|
| 516 |                 while (floor(d1) != d1) { | 
|---|
| 517 |                     d1 *= 10.0; | 
|---|
| 518 |                 } | 
|---|
| 519 |                 return ((int) d1);                /*    85   */ | 
|---|
| 520 |             } | 
|---|
| 521 |         } | 
|---|
| 522 |     } while (!feof(f)); | 
|---|
| 523 |  | 
|---|
| 524 |     fclose(f); | 
|---|
| 525 |     return 0; | 
|---|
| 526 | } | 
|---|
| 527 |  | 
|---|
| 528 | /* | 
|---|
| 529 |  * GetVersionFromFile -- | 
|---|
| 530 |  *      Looks for a match string in a file and then returns the version | 
|---|
| 531 |  *      following the match where a version is anything acceptable to | 
|---|
| 532 |  *      package provide or package ifneeded. | 
|---|
| 533 |  */ | 
|---|
| 534 |  | 
|---|
| 535 | const char * | 
|---|
| 536 | GetVersionFromFile( | 
|---|
| 537 |     const char *filename, | 
|---|
| 538 |     const char *match) | 
|---|
| 539 | { | 
|---|
| 540 |     size_t cbBuffer = 100; | 
|---|
| 541 |     static char szBuffer[100]; | 
|---|
| 542 |     char *szResult = NULL; | 
|---|
| 543 |     FILE *fp = fopen(filename, "rt"); | 
|---|
| 544 |  | 
|---|
| 545 |     if (fp != NULL) { | 
|---|
| 546 |         /* | 
|---|
| 547 |          * Read data until we see our match string. | 
|---|
| 548 |          */ | 
|---|
| 549 |  | 
|---|
| 550 |         while (fgets(szBuffer, cbBuffer, fp) != NULL) { | 
|---|
| 551 |             LPSTR p, q; | 
|---|
| 552 |  | 
|---|
| 553 |             p = strstr(szBuffer, match); | 
|---|
| 554 |             if (p != NULL) { | 
|---|
| 555 |                 /* | 
|---|
| 556 |                  * Skip to first digit. | 
|---|
| 557 |                  */ | 
|---|
| 558 |  | 
|---|
| 559 |                 while (*p && !isdigit(*p)) { | 
|---|
| 560 |                     ++p; | 
|---|
| 561 |                 } | 
|---|
| 562 |  | 
|---|
| 563 |                 /* | 
|---|
| 564 |                  * Find ending whitespace. | 
|---|
| 565 |                  */ | 
|---|
| 566 |  | 
|---|
| 567 |                 q = p; | 
|---|
| 568 |                 while (*q && (isalnum(*q) || *q == '.')) { | 
|---|
| 569 |                     ++q; | 
|---|
| 570 |                 } | 
|---|
| 571 |  | 
|---|
| 572 |                 memcpy(szBuffer, p, q - p); | 
|---|
| 573 |                 szBuffer[q-p] = 0; | 
|---|
| 574 |                 szResult = szBuffer; | 
|---|
| 575 |                 break; | 
|---|
| 576 |             } | 
|---|
| 577 |         } | 
|---|
| 578 |         fclose(fp); | 
|---|
| 579 |     } | 
|---|
| 580 |     return szResult; | 
|---|
| 581 | } | 
|---|
| 582 |  | 
|---|
| 583 | /* | 
|---|
| 584 |  * List helpers for the SubstituteFile function | 
|---|
| 585 |  */ | 
|---|
| 586 |  | 
|---|
| 587 | typedef struct list_item_t { | 
|---|
| 588 |     struct list_item_t *nextPtr; | 
|---|
| 589 |     char * key; | 
|---|
| 590 |     char * value; | 
|---|
| 591 | } list_item_t; | 
|---|
| 592 |  | 
|---|
| 593 | /* insert a list item into the list (list may be null) */ | 
|---|
| 594 | static list_item_t * | 
|---|
| 595 | list_insert(list_item_t **listPtrPtr, const char *key, const char *value) | 
|---|
| 596 | { | 
|---|
| 597 |     list_item_t *itemPtr = malloc(sizeof(list_item_t)); | 
|---|
| 598 |     if (itemPtr) { | 
|---|
| 599 |         itemPtr->key = strdup(key); | 
|---|
| 600 |         itemPtr->value = strdup(value); | 
|---|
| 601 |         itemPtr->nextPtr = NULL; | 
|---|
| 602 |  | 
|---|
| 603 |         while(*listPtrPtr) { | 
|---|
| 604 |             listPtrPtr = &(*listPtrPtr)->nextPtr; | 
|---|
| 605 |         } | 
|---|
| 606 |         *listPtrPtr = itemPtr; | 
|---|
| 607 |     } | 
|---|
| 608 |     return itemPtr; | 
|---|
| 609 | } | 
|---|
| 610 |  | 
|---|
| 611 | static void | 
|---|
| 612 | list_free(list_item_t **listPtrPtr) | 
|---|
| 613 | { | 
|---|
| 614 |     list_item_t *tmpPtr, *listPtr = *listPtrPtr; | 
|---|
| 615 |     while (listPtr) { | 
|---|
| 616 |         tmpPtr = listPtr; | 
|---|
| 617 |         listPtr = listPtr->nextPtr; | 
|---|
| 618 |         free(tmpPtr->key); | 
|---|
| 619 |         free(tmpPtr->value); | 
|---|
| 620 |         free(tmpPtr); | 
|---|
| 621 |     } | 
|---|
| 622 | } | 
|---|
| 623 |  | 
|---|
| 624 | /* | 
|---|
| 625 |  * SubstituteFile -- | 
|---|
| 626 |  *      As windows doesn't provide anything useful like sed and it's unreliable | 
|---|
| 627 |  *      to use the tclsh you are building against (consider x-platform builds - | 
|---|
| 628 |  *      eg compiling AMD64 target from IX86) we provide a simple substitution | 
|---|
| 629 |  *      option here to handle autoconf style substitutions. | 
|---|
| 630 |  *      The substitution file is whitespace and line delimited. The file should | 
|---|
| 631 |  *      consist of lines matching the regular expression: | 
|---|
| 632 |  *        \s*\S+\s+\S*$ | 
|---|
| 633 |  * | 
|---|
| 634 |  *      Usage is something like: | 
|---|
| 635 |  *        nmakehlp -S << $** > $@ | 
|---|
| 636 |  *        @PACKAGE_NAME@ $(PACKAGE_NAME) | 
|---|
| 637 |  *        @PACKAGE_VERSION@ $(PACKAGE_VERSION) | 
|---|
| 638 |  *        << | 
|---|
| 639 |  */ | 
|---|
| 640 |  | 
|---|
| 641 | int | 
|---|
| 642 | SubstituteFile( | 
|---|
| 643 |     const char *substitutions, | 
|---|
| 644 |     const char *filename) | 
|---|
| 645 | { | 
|---|
| 646 |     size_t cbBuffer = 1024; | 
|---|
| 647 |     static char szBuffer[1024], szCopy[1024]; | 
|---|
| 648 |     char *szResult = NULL; | 
|---|
| 649 |     list_item_t *substPtr = NULL; | 
|---|
| 650 |     FILE *fp, *sp; | 
|---|
| 651 |  | 
|---|
| 652 |     fp = fopen(filename, "rt"); | 
|---|
| 653 |     if (fp != NULL) { | 
|---|
| 654 |  | 
|---|
| 655 |         /* | 
|---|
| 656 |          * Build a list of substutitions from the first filename | 
|---|
| 657 |          */ | 
|---|
| 658 |  | 
|---|
| 659 |         sp = fopen(substitutions, "rt"); | 
|---|
| 660 |         if (sp != NULL) { | 
|---|
| 661 |             while (fgets(szBuffer, cbBuffer, sp) != NULL) { | 
|---|
| 662 |                 char *ks, *ke, *vs, *ve; | 
|---|
| 663 |                 ks = szBuffer; | 
|---|
| 664 |                 while (ks && *ks && isspace(*ks)) ++ks; | 
|---|
| 665 |                 ke = ks; | 
|---|
| 666 |                 while (ke && *ke && !isspace(*ke)) ++ke; | 
|---|
| 667 |                 vs = ke; | 
|---|
| 668 |                 while (vs && *vs && isspace(*vs)) ++vs; | 
|---|
| 669 |                 ve = vs; | 
|---|
| 670 |                 while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; | 
|---|
| 671 |                 *ke = 0, *ve = 0; | 
|---|
| 672 |                 list_insert(&substPtr, ks, vs); | 
|---|
| 673 |             } | 
|---|
| 674 |             fclose(sp); | 
|---|
| 675 |         } | 
|---|
| 676 |  | 
|---|
| 677 |         /* debug: dump the list */ | 
|---|
| 678 | #ifdef _DEBUG | 
|---|
| 679 |         { | 
|---|
| 680 |             int n = 0; | 
|---|
| 681 |             list_item_t *p = NULL; | 
|---|
| 682 |             for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { | 
|---|
| 683 |                 fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); | 
|---|
| 684 |             } | 
|---|
| 685 |         } | 
|---|
| 686 | #endif | 
|---|
| 687 |          | 
|---|
| 688 |         /* | 
|---|
| 689 |          * Run the substitutions over each line of the input | 
|---|
| 690 |          */ | 
|---|
| 691 |          | 
|---|
| 692 |         while (fgets(szBuffer, cbBuffer, fp) != NULL) { | 
|---|
| 693 |             list_item_t *p = NULL; | 
|---|
| 694 |             for (p = substPtr; p != NULL; p = p->nextPtr) { | 
|---|
| 695 |                 char *m = strstr(szBuffer, p->key); | 
|---|
| 696 |                 if (m) { | 
|---|
| 697 |                     char *cp, *op, *sp; | 
|---|
| 698 |                     cp = szCopy; | 
|---|
| 699 |                     op = szBuffer; | 
|---|
| 700 |                     while (op != m) *cp++ = *op++; | 
|---|
| 701 |                     sp = p->value; | 
|---|
| 702 |                     while (sp && *sp) *cp++ = *sp++; | 
|---|
| 703 |                     op += strlen(p->key); | 
|---|
| 704 |                     while (*op) *cp++ = *op++; | 
|---|
| 705 |                     *cp = 0; | 
|---|
| 706 |                     memcpy(szBuffer, szCopy, sizeof(szCopy)); | 
|---|
| 707 |                 } | 
|---|
| 708 |             } | 
|---|
| 709 |             printf(szBuffer); | 
|---|
| 710 |         } | 
|---|
| 711 |          | 
|---|
| 712 |         list_free(&substPtr); | 
|---|
| 713 |     } | 
|---|
| 714 |     fclose(fp); | 
|---|
| 715 |     return 0; | 
|---|
| 716 | } | 
|---|
| 717 |  | 
|---|
| 718 | /* | 
|---|
| 719 |  * Local variables: | 
|---|
| 720 |  *   mode: c | 
|---|
| 721 |  *   c-basic-offset: 4 | 
|---|
| 722 |  *   fill-column: 78 | 
|---|
| 723 |  *   indent-tabs-mode: t | 
|---|
| 724 |  *   tab-width: 8 | 
|---|
| 725 |  * End: | 
|---|
| 726 |  */ | 
|---|