| [25] | 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 |  */ | 
|---|