os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/nmakehlp.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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  *
     9  * See the file "license.terms" for information on usage and redistribution
    10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    11  *
    12  * ----------------------------------------------------------------------------
    13  * RCS: @(#) $Id: nmakehlp.c,v 1.1.4.4 2006/10/18 08:49:33 patthoyts Exp $
    14  * ----------------------------------------------------------------------------
    15  */
    16 
    17 #define _CRT_SECURE_NO_DEPRECATE
    18 #include <windows.h>
    19 #pragma comment (lib, "user32.lib")
    20 #pragma comment (lib, "kernel32.lib")
    21 #include <stdio.h>
    22 #include <math.h>
    23 #if defined(_M_IA64) || defined(_M_AMD64)
    24 #pragma comment(lib, "bufferoverflowU")
    25 #endif
    26 
    27 /* ISO hack for dumb VC++ */
    28 #ifdef _MSC_VER
    29 #define   snprintf	_snprintf
    30 #endif
    31 
    32 
    33 
    34 /* protos */
    35 
    36 int		CheckForCompilerFeature(const char *option);
    37 int		CheckForLinkerFeature(const char *option);
    38 int		IsIn(const char *string, const char *substring);
    39 int		GrepForDefine(const char *file, const char *string);
    40 DWORD WINAPI	ReadFromPipe(LPVOID args);
    41 
    42 /* globals */
    43 
    44 #define CHUNK	25
    45 #define STATICBUFFERSIZE    1000
    46 typedef struct {
    47     HANDLE pipe;
    48     char buffer[STATICBUFFERSIZE];
    49 } pipeinfo;
    50 
    51 pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
    52 pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};
    53 
    54 /*
    55  * exitcodes: 0 == no, 1 == yes, 2 == error
    56  */
    57 
    58 int
    59 main(
    60     int argc,
    61     char *argv[])
    62 {
    63     char msg[300];
    64     DWORD dwWritten;
    65     int chars;
    66 
    67     /*
    68      * Make sure children (cl.exe and link.exe) are kept quiet.
    69      */
    70 
    71     SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
    72 
    73     /*
    74      * Make sure the compiler and linker aren't effected by the outside world.
    75      */
    76 
    77     SetEnvironmentVariable("CL", "");
    78     SetEnvironmentVariable("LINK", "");
    79 
    80     if (argc > 1 && *argv[1] == '-') {
    81 	switch (*(argv[1]+1)) {
    82 	case 'c':
    83 	    if (argc != 3) {
    84 		chars = snprintf(msg, sizeof(msg) - 1,
    85 		        "usage: %s -c <compiler option>\n"
    86 			"Tests for whether cl.exe supports an option\n"
    87 			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
    88 		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
    89 			&dwWritten, NULL);
    90 		return 2;
    91 	    }
    92 	    return CheckForCompilerFeature(argv[2]);
    93 	case 'l':
    94 	    if (argc != 3) {
    95 		chars = snprintf(msg, sizeof(msg) - 1,
    96 	       		"usage: %s -l <linker option>\n"
    97 			"Tests for whether link.exe supports an option\n"
    98 			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
    99 		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
   100 			&dwWritten, NULL);
   101 		return 2;
   102 	    }
   103 	    return CheckForLinkerFeature(argv[2]);
   104 	case 'f':
   105 	    if (argc == 2) {
   106 		chars = snprintf(msg, sizeof(msg) - 1,
   107 			"usage: %s -f <string> <substring>\n"
   108 			"Find a substring within another\n"
   109 			"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
   110 		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
   111 			&dwWritten, NULL);
   112 		return 2;
   113 	    } else if (argc == 3) {
   114 		/*
   115 		 * If the string is blank, there is no match.
   116 		 */
   117 
   118 		return 0;
   119 	    } else {
   120 		return IsIn(argv[2], argv[3]);
   121 	    }
   122 	case 'g':
   123 	    if (argc == 2) {
   124 		chars = snprintf(msg, sizeof(msg) - 1,
   125 			"usage: %s -g <file> <string>\n"
   126 			"grep for a #define\n"
   127 			"exitcodes: integer of the found string (no decimals)\n",
   128 			argv[0]);
   129 		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
   130 			&dwWritten, NULL);
   131 		return 2;
   132 	    }
   133 	    return GrepForDefine(argv[2], argv[3]);
   134 	}
   135     }
   136     chars = snprintf(msg, sizeof(msg) - 1,
   137 	    "usage: %s -c|-l|-f ...\n"
   138 	    "This is a little helper app to equalize shell differences between WinNT and\n"
   139 	    "Win9x and get nmake.exe to accomplish its job.\n",
   140 	    argv[0]);
   141     WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
   142     return 2;
   143 }
   144 
   145 int
   146 CheckForCompilerFeature(
   147     const char *option)
   148 {
   149     STARTUPINFO si;
   150     PROCESS_INFORMATION pi;
   151     SECURITY_ATTRIBUTES sa;
   152     DWORD threadID;
   153     char msg[300];
   154     BOOL ok;
   155     HANDLE hProcess, h, pipeThreads[2];
   156     char cmdline[100];
   157 
   158     hProcess = GetCurrentProcess();
   159 
   160     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
   161     ZeroMemory(&si, sizeof(STARTUPINFO));
   162     si.cb = sizeof(STARTUPINFO);
   163     si.dwFlags   = STARTF_USESTDHANDLES;
   164     si.hStdInput = INVALID_HANDLE_VALUE;
   165 
   166     ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
   167     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
   168     sa.lpSecurityDescriptor = NULL;
   169     sa.bInheritHandle = FALSE;
   170 
   171     /*
   172      * Create a non-inheritible pipe.
   173      */
   174 
   175     CreatePipe(&Out.pipe, &h, &sa, 0);
   176 
   177     /*
   178      * Dupe the write side, make it inheritible, and close the original.
   179      */
   180 
   181     DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
   182 	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
   183 
   184     /*
   185      * Same as above, but for the error side.
   186      */
   187 
   188     CreatePipe(&Err.pipe, &h, &sa, 0);
   189     DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
   190 	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
   191 
   192     /*
   193      * Base command line.
   194      */
   195 
   196     lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X ");
   197 
   198     /*
   199      * Append our option for testing
   200      */
   201 
   202     lstrcat(cmdline, option);
   203 
   204     /*
   205      * Filename to compile, which exists, but is nothing and empty.
   206      */
   207 
   208     lstrcat(cmdline, " .\\nul");
   209 
   210     ok = CreateProcess(
   211 	    NULL,	    /* Module name. */
   212 	    cmdline,	    /* Command line. */
   213 	    NULL,	    /* Process handle not inheritable. */
   214 	    NULL,	    /* Thread handle not inheritable. */
   215 	    TRUE,	    /* yes, inherit handles. */
   216 	    DETACHED_PROCESS, /* No console for you. */
   217 	    NULL,	    /* Use parent's environment block. */
   218 	    NULL,	    /* Use parent's starting directory. */
   219 	    &si,	    /* Pointer to STARTUPINFO structure. */
   220 	    &pi);	    /* Pointer to PROCESS_INFORMATION structure. */
   221 
   222     if (!ok) {
   223 	DWORD err = GetLastError();
   224 	int chars = snprintf(msg, sizeof(msg) - 1,
   225 		"Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
   226 
   227 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
   228 		FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
   229 		(300-chars), 0);
   230 	WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
   231 	return 2;
   232     }
   233 
   234     /*
   235      * Close our references to the write handles that have now been inherited.
   236      */
   237 
   238     CloseHandle(si.hStdOutput);
   239     CloseHandle(si.hStdError);
   240 
   241     WaitForInputIdle(pi.hProcess, 5000);
   242     CloseHandle(pi.hThread);
   243 
   244     /*
   245      * Start the pipe reader threads.
   246      */
   247 
   248     pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
   249     pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
   250 
   251     /*
   252      * Block waiting for the process to end.
   253      */
   254 
   255     WaitForSingleObject(pi.hProcess, INFINITE);
   256     CloseHandle(pi.hProcess);
   257 
   258     /*
   259      * Wait for our pipe to get done reading, should it be a little slow.
   260      */
   261 
   262     WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
   263     CloseHandle(pipeThreads[0]);
   264     CloseHandle(pipeThreads[1]);
   265 
   266     /*
   267      * Look for the commandline warning code in both streams.
   268      *  - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
   269      */
   270 
   271     return !(strstr(Out.buffer, "D4002") != NULL
   272              || strstr(Err.buffer, "D4002") != NULL
   273              || strstr(Out.buffer, "D9002") != NULL
   274              || strstr(Err.buffer, "D9002") != NULL);
   275 }
   276 
   277 int
   278 CheckForLinkerFeature(
   279     const char *option)
   280 {
   281     STARTUPINFO si;
   282     PROCESS_INFORMATION pi;
   283     SECURITY_ATTRIBUTES sa;
   284     DWORD threadID;
   285     char msg[300];
   286     BOOL ok;
   287     HANDLE hProcess, h, pipeThreads[2];
   288     char cmdline[100];
   289 
   290     hProcess = GetCurrentProcess();
   291 
   292     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
   293     ZeroMemory(&si, sizeof(STARTUPINFO));
   294     si.cb = sizeof(STARTUPINFO);
   295     si.dwFlags   = STARTF_USESTDHANDLES;
   296     si.hStdInput = INVALID_HANDLE_VALUE;
   297 
   298     ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
   299     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
   300     sa.lpSecurityDescriptor = NULL;
   301     sa.bInheritHandle = TRUE;
   302 
   303     /*
   304      * Create a non-inheritible pipe.
   305      */
   306 
   307     CreatePipe(&Out.pipe, &h, &sa, 0);
   308 
   309     /*
   310      * Dupe the write side, make it inheritible, and close the original.
   311      */
   312 
   313     DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
   314 	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
   315 
   316     /*
   317      * Same as above, but for the error side.
   318      */
   319 
   320     CreatePipe(&Err.pipe, &h, &sa, 0);
   321     DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
   322 	    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
   323 
   324     /*
   325      * Base command line.
   326      */
   327 
   328     lstrcpy(cmdline, "link.exe -nologo ");
   329 
   330     /*
   331      * Append our option for testing.
   332      */
   333 
   334     lstrcat(cmdline, option);
   335 
   336     ok = CreateProcess(
   337 	    NULL,	    /* Module name. */
   338 	    cmdline,	    /* Command line. */
   339 	    NULL,	    /* Process handle not inheritable. */
   340 	    NULL,	    /* Thread handle not inheritable. */
   341 	    TRUE,	    /* yes, inherit handles. */
   342 	    DETACHED_PROCESS, /* No console for you. */
   343 	    NULL,	    /* Use parent's environment block. */
   344 	    NULL,	    /* Use parent's starting directory. */
   345 	    &si,	    /* Pointer to STARTUPINFO structure. */
   346 	    &pi);	    /* Pointer to PROCESS_INFORMATION structure. */
   347 
   348     if (!ok) {
   349 	DWORD err = GetLastError();
   350 	int chars = snprintf(msg, sizeof(msg) - 1,
   351 		"Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
   352 
   353 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
   354 		FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
   355 		(300-chars), 0);
   356 	WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
   357 	return 2;
   358     }
   359 
   360     /*
   361      * Close our references to the write handles that have now been inherited.
   362      */
   363 
   364     CloseHandle(si.hStdOutput);
   365     CloseHandle(si.hStdError);
   366 
   367     WaitForInputIdle(pi.hProcess, 5000);
   368     CloseHandle(pi.hThread);
   369 
   370     /*
   371      * Start the pipe reader threads.
   372      */
   373 
   374     pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
   375     pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
   376 
   377     /*
   378      * Block waiting for the process to end.
   379      */
   380 
   381     WaitForSingleObject(pi.hProcess, INFINITE);
   382     CloseHandle(pi.hProcess);
   383 
   384     /*
   385      * Wait for our pipe to get done reading, should it be a little slow.
   386      */
   387 
   388     WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
   389     CloseHandle(pipeThreads[0]);
   390     CloseHandle(pipeThreads[1]);
   391 
   392     /*
   393      * Look for the commandline warning code in the stderr stream.
   394      */
   395 
   396     return !(strstr(Out.buffer, "LNK1117") != NULL ||
   397              strstr(Err.buffer, "LNK1117") != NULL ||
   398              strstr(Out.buffer, "LNK4044") != NULL ||
   399              strstr(Err.buffer, "LNK4044") != NULL);
   400 }
   401 
   402 DWORD WINAPI
   403 ReadFromPipe(
   404     LPVOID args)
   405 {
   406     pipeinfo *pi = (pipeinfo *) args;
   407     char *lastBuf = pi->buffer;
   408     DWORD dwRead;
   409     BOOL ok;
   410 
   411   again:
   412     if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
   413 	CloseHandle(pi->pipe);
   414 	return (DWORD)-1;
   415     }
   416     ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
   417     if (!ok || dwRead == 0) {
   418 	CloseHandle(pi->pipe);
   419 	return 0;
   420     }
   421     lastBuf += dwRead;
   422     goto again;
   423 
   424     return 0;  /* makes the compiler happy */
   425 }
   426 
   427 int
   428 IsIn(
   429     const char *string,
   430     const char *substring)
   431 {
   432     return (strstr(string, substring) != NULL);
   433 }
   434 
   435 /*
   436  * Find a specified #define by name.
   437  *
   438  * If the line is '#define TCL_VERSION "8.5"', it returns 85 as the result.
   439  */
   440 
   441 int
   442 GrepForDefine(
   443     const char *file,
   444     const char *string)
   445 {
   446     FILE *f;
   447     char s1[51], s2[51], s3[51];
   448     int r = 0;
   449     double d1;
   450 
   451     f = fopen(file, "rt");
   452     if (f == NULL) {
   453 	return 0;
   454     }
   455 
   456     do {
   457 	r = fscanf(f, "%50s", s1);
   458 	if (r == 1 && !strcmp(s1, "#define")) {
   459 	    /*
   460 	     * Get next two words.
   461 	     */
   462 
   463 	    r = fscanf(f, "%50s %50s", s2, s3);
   464 	    if (r != 2) {
   465 		continue;
   466 	    }
   467 
   468 	    /*
   469 	     * Is the first word what we're looking for?
   470 	     */
   471 
   472 	    if (!strcmp(s2, string)) {
   473 		fclose(f);
   474 
   475 		/*
   476 		 * Add 1 past first double quote char. "8.5"
   477 		 */
   478 
   479 		d1 = atof(s3 + 1);		  /*    8.5  */
   480 		while (floor(d1) != d1) {
   481 		    d1 *= 10.0;
   482 		}
   483 		return ((int) d1);		  /*    85   */
   484 	    }
   485 	}
   486     } while (!feof(f));
   487 
   488     fclose(f);
   489     return 0;
   490 }