| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define _CRT_SECURE_NO_DEPRECATE |
| #include <windows.h> |
| #define NO_SHLWAPI_GDI |
| #define NO_SHLWAPI_STREAM |
| #define NO_SHLWAPI_REG |
| #include <shlwapi.h> |
| #pragma comment (lib, "user32.lib") |
| #pragma comment (lib, "kernel32.lib") |
| #pragma comment (lib, "shlwapi.lib") |
| #include <stdio.h> |
| #include <math.h> |
| |
| |
| |
| |
| #if defined(_M_IA64) || defined(_M_AMD64) |
| #if _MSC_VER >= 1400 && _MSC_VER < 1500 |
| #pragma comment(lib, "bufferoverflowU") |
| #endif |
| #endif |
| |
| |
| #ifdef _MSC_VER |
| #define snprintf _snprintf |
| #endif |
| |
| |
| |
| |
| |
| static int CheckForCompilerFeature(const char *option); |
| static int CheckForLinkerFeature(const char *option); |
| static int IsIn(const char *string, const char *substring); |
| static int SubstituteFile(const char *substs, const char *filename); |
| static int QualifyPath(const char *path); |
| static const char *GetVersionFromFile(const char *filename, const char *match); |
| static DWORD WINAPI ReadFromPipe(LPVOID args); |
| |
| |
| |
| #define CHUNK 25 |
| #define STATICBUFFERSIZE 1000 |
| typedef struct { |
| HANDLE pipe; |
| char buffer[STATICBUFFERSIZE]; |
| } pipeinfo; |
| |
| pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; |
| pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; |
| |
| |
| |
| |
| |
| int |
| main( |
| int argc, |
| char *argv[]) |
| { |
| char msg[300]; |
| DWORD dwWritten; |
| int chars; |
| |
| |
| |
| |
| |
| SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
| |
| |
| |
| |
| |
| SetEnvironmentVariable("CL", ""); |
| SetEnvironmentVariable("LINK", ""); |
| |
| if (argc > 1 && *argv[1] == '-') { |
| switch (*(argv[1]+1)) { |
| case 'c': |
| if (argc != 3) { |
| chars = snprintf(msg, sizeof(msg) - 1, |
| "usage: %s -c <compiler option>\n" |
| "Tests for whether cl.exe supports an option\n" |
| "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
| &dwWritten, NULL); |
| return 2; |
| } |
| return CheckForCompilerFeature(argv[2]); |
| case 'l': |
| if (argc != 3) { |
| chars = snprintf(msg, sizeof(msg) - 1, |
| "usage: %s -l <linker option>\n" |
| "Tests for whether link.exe supports an option\n" |
| "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
| &dwWritten, NULL); |
| return 2; |
| } |
| return CheckForLinkerFeature(argv[2]); |
| case 'f': |
| if (argc == 2) { |
| chars = snprintf(msg, sizeof(msg) - 1, |
| "usage: %s -f <string> <substring>\n" |
| "Find a substring within another\n" |
| "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
| &dwWritten, NULL); |
| return 2; |
| } else if (argc == 3) { |
| |
| |
| |
| |
| return 0; |
| } else { |
| return IsIn(argv[2], argv[3]); |
| } |
| case 's': |
| if (argc == 2) { |
| chars = snprintf(msg, sizeof(msg) - 1, |
| "usage: %s -s <substitutions file> <file>\n" |
| "Perform a set of string map type substutitions on a file\n" |
| "exitcodes: 0\n", |
| argv[0]); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
| &dwWritten, NULL); |
| return 2; |
| } |
| return SubstituteFile(argv[2], argv[3]); |
| case 'V': |
| if (argc != 4) { |
| chars = snprintf(msg, sizeof(msg) - 1, |
| "usage: %s -V filename matchstring\n" |
| "Extract a version from a file:\n" |
| "eg: pkgIndex.tcl \"package ifneeded http\"", |
| argv[0]); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
| &dwWritten, NULL); |
| return 0; |
| } |
| printf("%s\n", GetVersionFromFile(argv[2], argv[3])); |
| return 0; |
| case 'Q': |
| if (argc != 3) { |
| chars = snprintf(msg, sizeof(msg) - 1, |
| "usage: %s -Q path\n" |
| "Emit the fully qualified path\n" |
| "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
| &dwWritten, NULL); |
| return 2; |
| } |
| return QualifyPath(argv[2]); |
| } |
| } |
| chars = snprintf(msg, sizeof(msg) - 1, |
| "usage: %s -c|-f|-l|-Q|-s|-V ...\n" |
| "This is a little helper app to equalize shell differences between WinNT and\n" |
| "Win9x and get nmake.exe to accomplish its job.\n", |
| argv[0]); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); |
| return 2; |
| } |
| |
| static int |
| CheckForCompilerFeature( |
| const char *option) |
| { |
| STARTUPINFO si; |
| PROCESS_INFORMATION pi; |
| SECURITY_ATTRIBUTES sa; |
| DWORD threadID; |
| char msg[300]; |
| BOOL ok; |
| HANDLE hProcess, h, pipeThreads[2]; |
| char cmdline[100]; |
| |
| hProcess = GetCurrentProcess(); |
| |
| ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); |
| ZeroMemory(&si, sizeof(STARTUPINFO)); |
| si.cb = sizeof(STARTUPINFO); |
| si.dwFlags = STARTF_USESTDHANDLES; |
| si.hStdInput = INVALID_HANDLE_VALUE; |
| |
| ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); |
| sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
| sa.lpSecurityDescriptor = NULL; |
| sa.bInheritHandle = FALSE; |
| |
| |
| |
| |
| |
| CreatePipe(&Out.pipe, &h, &sa, 0); |
| |
| |
| |
| |
| |
| DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, |
| DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); |
| |
| |
| |
| |
| |
| CreatePipe(&Err.pipe, &h, &sa, 0); |
| DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, |
| DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); |
| |
| |
| |
| |
| |
| lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); |
| |
| |
| |
| |
| |
| lstrcat(cmdline, option); |
| |
| |
| |
| |
| |
| lstrcat(cmdline, " .\\nul"); |
| |
| ok = CreateProcess( |
| NULL, |
| cmdline, |
| NULL, |
| NULL, |
| TRUE, |
| DETACHED_PROCESS, |
| NULL, |
| NULL, |
| &si, |
| &pi); |
| |
| if (!ok) { |
| DWORD err = GetLastError(); |
| int chars = snprintf(msg, sizeof(msg) - 1, |
| "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); |
| |
| FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| |
| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], |
| (300-chars), 0); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); |
| return 2; |
| } |
| |
| |
| |
| |
| |
| CloseHandle(si.hStdOutput); |
| CloseHandle(si.hStdError); |
| |
| WaitForInputIdle(pi.hProcess, 5000); |
| CloseHandle(pi.hThread); |
| |
| |
| |
| |
| |
| pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); |
| pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); |
| |
| |
| |
| |
| |
| WaitForSingleObject(pi.hProcess, INFINITE); |
| CloseHandle(pi.hProcess); |
| |
| |
| |
| |
| |
| WaitForMultipleObjects(2, pipeThreads, TRUE, 500); |
| CloseHandle(pipeThreads[0]); |
| CloseHandle(pipeThreads[1]); |
| |
| |
| |
| |
| |
| |
| return !(strstr(Out.buffer, "D4002") != NULL |
| || strstr(Err.buffer, "D4002") != NULL |
| || strstr(Out.buffer, "D9002") != NULL |
| || strstr(Err.buffer, "D9002") != NULL |
| || strstr(Out.buffer, "D2021") != NULL |
| || strstr(Err.buffer, "D2021") != NULL); |
| } |
| |
| static int |
| CheckForLinkerFeature( |
| const char *option) |
| { |
| STARTUPINFO si; |
| PROCESS_INFORMATION pi; |
| SECURITY_ATTRIBUTES sa; |
| DWORD threadID; |
| char msg[300]; |
| BOOL ok; |
| HANDLE hProcess, h, pipeThreads[2]; |
| char cmdline[100]; |
| |
| hProcess = GetCurrentProcess(); |
| |
| ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); |
| ZeroMemory(&si, sizeof(STARTUPINFO)); |
| si.cb = sizeof(STARTUPINFO); |
| si.dwFlags = STARTF_USESTDHANDLES; |
| si.hStdInput = INVALID_HANDLE_VALUE; |
| |
| ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); |
| sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
| sa.lpSecurityDescriptor = NULL; |
| sa.bInheritHandle = TRUE; |
| |
| |
| |
| |
| |
| CreatePipe(&Out.pipe, &h, &sa, 0); |
| |
| |
| |
| |
| |
| DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, |
| DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); |
| |
| |
| |
| |
| |
| CreatePipe(&Err.pipe, &h, &sa, 0); |
| DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, |
| DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); |
| |
| |
| |
| |
| |
| lstrcpy(cmdline, "link.exe -nologo "); |
| |
| |
| |
| |
| |
| lstrcat(cmdline, option); |
| |
| ok = CreateProcess( |
| NULL, |
| cmdline, |
| NULL, |
| NULL, |
| TRUE, |
| DETACHED_PROCESS, |
| NULL, |
| NULL, |
| &si, |
| &pi); |
| |
| if (!ok) { |
| DWORD err = GetLastError(); |
| int chars = snprintf(msg, sizeof(msg) - 1, |
| "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); |
| |
| FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| |
| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], |
| (300-chars), 0); |
| WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); |
| return 2; |
| } |
| |
| |
| |
| |
| |
| CloseHandle(si.hStdOutput); |
| CloseHandle(si.hStdError); |
| |
| WaitForInputIdle(pi.hProcess, 5000); |
| CloseHandle(pi.hThread); |
| |
| |
| |
| |
| |
| pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); |
| pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); |
| |
| |
| |
| |
| |
| WaitForSingleObject(pi.hProcess, INFINITE); |
| CloseHandle(pi.hProcess); |
| |
| |
| |
| |
| |
| WaitForMultipleObjects(2, pipeThreads, TRUE, 500); |
| CloseHandle(pipeThreads[0]); |
| CloseHandle(pipeThreads[1]); |
| |
| |
| |
| |
| |
| return !(strstr(Out.buffer, "LNK1117") != NULL || |
| strstr(Err.buffer, "LNK1117") != NULL || |
| strstr(Out.buffer, "LNK4044") != NULL || |
| strstr(Err.buffer, "LNK4044") != NULL); |
| } |
| |
| static DWORD WINAPI |
| ReadFromPipe( |
| LPVOID args) |
| { |
| pipeinfo *pi = (pipeinfo *) args; |
| char *lastBuf = pi->buffer; |
| DWORD dwRead; |
| BOOL ok; |
| |
| again: |
| if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { |
| CloseHandle(pi->pipe); |
| return (DWORD)-1; |
| } |
| ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); |
| if (!ok || dwRead == 0) { |
| CloseHandle(pi->pipe); |
| return 0; |
| } |
| lastBuf += dwRead; |
| goto again; |
| |
| return 0; |
| } |
| |
| static int |
| IsIn( |
| const char *string, |
| const char *substring) |
| { |
| return (strstr(string, substring) != NULL); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| static const char * |
| GetVersionFromFile( |
| const char *filename, |
| const char *match) |
| { |
| size_t cbBuffer = 100; |
| static char szBuffer[100]; |
| char *szResult = NULL; |
| FILE *fp = fopen(filename, "rt"); |
| |
| if (fp != NULL) { |
| |
| |
| |
| |
| while (fgets(szBuffer, cbBuffer, fp) != NULL) { |
| LPSTR p, q; |
| |
| p = strstr(szBuffer, match); |
| if (p != NULL) { |
| |
| |
| |
| |
| while (*p && !isdigit(*p)) { |
| ++p; |
| } |
| |
| |
| |
| |
| |
| q = p; |
| while (*q && (isalnum(*q) || *q == '.')) { |
| ++q; |
| } |
| |
| memcpy(szBuffer, p, q - p); |
| szBuffer[q-p] = 0; |
| szResult = szBuffer; |
| break; |
| } |
| } |
| fclose(fp); |
| } |
| return szResult; |
| } |
| |
| |
| |
| |
| |
| typedef struct list_item_t { |
| struct list_item_t *nextPtr; |
| char * key; |
| char * value; |
| } list_item_t; |
| |
| |
| static list_item_t * |
| list_insert(list_item_t **listPtrPtr, const char *key, const char *value) |
| { |
| list_item_t *itemPtr = malloc(sizeof(list_item_t)); |
| if (itemPtr) { |
| itemPtr->key = strdup(key); |
| itemPtr->value = strdup(value); |
| itemPtr->nextPtr = NULL; |
| |
| while(*listPtrPtr) { |
| listPtrPtr = &(*listPtrPtr)->nextPtr; |
| } |
| *listPtrPtr = itemPtr; |
| } |
| return itemPtr; |
| } |
| |
| static void |
| list_free(list_item_t **listPtrPtr) |
| { |
| list_item_t *tmpPtr, *listPtr = *listPtrPtr; |
| while (listPtr) { |
| tmpPtr = listPtr; |
| listPtr = listPtr->nextPtr; |
| free(tmpPtr->key); |
| free(tmpPtr->value); |
| free(tmpPtr); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int |
| SubstituteFile( |
| const char *substitutions, |
| const char *filename) |
| { |
| size_t cbBuffer = 1024; |
| static char szBuffer[1024], szCopy[1024]; |
| char *szResult = NULL; |
| list_item_t *substPtr = NULL; |
| FILE *fp, *sp; |
| |
| fp = fopen(filename, "rt"); |
| if (fp != NULL) { |
| |
| |
| |
| |
| |
| sp = fopen(substitutions, "rt"); |
| if (sp != NULL) { |
| while (fgets(szBuffer, cbBuffer, sp) != NULL) { |
| unsigned char *ks, *ke, *vs, *ve; |
| ks = (unsigned char*)szBuffer; |
| while (ks && *ks && isspace(*ks)) ++ks; |
| ke = ks; |
| while (ke && *ke && !isspace(*ke)) ++ke; |
| vs = ke; |
| while (vs && *vs && isspace(*vs)) ++vs; |
| ve = vs; |
| while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; |
| *ke = 0, *ve = 0; |
| list_insert(&substPtr, (char*)ks, (char*)vs); |
| } |
| fclose(sp); |
| } |
| |
| |
| #ifdef _DEBUG |
| { |
| int n = 0; |
| list_item_t *p = NULL; |
| for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { |
| fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); |
| } |
| } |
| #endif |
| |
| |
| |
| |
| |
| while (fgets(szBuffer, cbBuffer, fp) != NULL) { |
| list_item_t *p = NULL; |
| for (p = substPtr; p != NULL; p = p->nextPtr) { |
| char *m = strstr(szBuffer, p->key); |
| if (m) { |
| char *cp, *op, *sp; |
| cp = szCopy; |
| op = szBuffer; |
| while (op != m) *cp++ = *op++; |
| sp = p->value; |
| while (sp && *sp) *cp++ = *sp++; |
| op += strlen(p->key); |
| while (*op) *cp++ = *op++; |
| *cp = 0; |
| memcpy(szBuffer, szCopy, sizeof(szCopy)); |
| } |
| } |
| printf(szBuffer); |
| } |
| |
| list_free(&substPtr); |
| } |
| fclose(fp); |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int |
| QualifyPath( |
| const char *szPath) |
| { |
| char szCwd[MAX_PATH + 1]; |
| char szTmp[MAX_PATH + 1]; |
| char *p; |
| GetCurrentDirectory(MAX_PATH, szCwd); |
| while ((p = strchr(szPath, '/')) && *p) |
| *p = '\\'; |
| PathCombine(szTmp, szCwd, szPath); |
| PathCanonicalize(szCwd, szTmp); |
| printf("%s\n", szCwd); |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |