633 lines
14 KiB
C
633 lines
14 KiB
C
//
|
|
// GUIDLIB2.C
|
|
//
|
|
// Copyright Microsoft Corporation, 1995-1996
|
|
//
|
|
// Tracy Sharpe, 07 Apr 1996
|
|
//
|
|
// Builds a static library that contains seperate object records for each GUID
|
|
// declared in the specified source file.
|
|
//
|
|
// This is version 2.0 of the GUIDLIB tool. This version of the tool uses the
|
|
// Microsoft C preprocessor to handle the bulk of the hard work. Also, this
|
|
// version can handle much more
|
|
//
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include "messages.h"
|
|
|
|
// Version 1.0
|
|
int
|
|
__cdecl
|
|
oldmain(
|
|
int argc,
|
|
char* argv[]
|
|
);
|
|
|
|
char g_szInputFile[MAX_PATH];
|
|
char g_szOutputFile[MAX_PATH];
|
|
char g_szObjectModulePrefix[MAX_PATH];
|
|
char g_szCPPCMD[MAX_PATH] = "cl";
|
|
char g_szCPPOPT[MAX_PATH] = "";
|
|
char g_szLIBCMD[MAX_PATH] = "link";
|
|
BOOL g_fLIBCMDOverride;
|
|
BOOL g_fWantHelp;
|
|
BOOL g_fNOCVDEBUG = FALSE;
|
|
|
|
typedef enum _ARGTYPE {
|
|
ARGTYPE_CPPCMD,
|
|
ARGTYPE_CPPOPT,
|
|
ARGTYPE_LIBCMD,
|
|
ARGTYPE_OUT,
|
|
ARGTYPE_HELP,
|
|
ARGTYPE_LEGO,
|
|
ARGTYPE_NOCVDEBUG
|
|
} ARGTYPE;
|
|
|
|
typedef struct _ARGOPTION {
|
|
ARGTYPE type;
|
|
LPCSTR pszOption;
|
|
BOOL fExpectArg;
|
|
} ARGOPTION;
|
|
|
|
ARGOPTION g_argopts[] = {
|
|
{ ARGTYPE_CPPCMD, "cpp_cmd", TRUE },
|
|
{ ARGTYPE_CPPOPT, "cpp_opt", TRUE },
|
|
{ ARGTYPE_LIBCMD, "lib_cmd", TRUE },
|
|
{ ARGTYPE_OUT, "out", TRUE },
|
|
{ ARGTYPE_HELP, "?", FALSE},
|
|
{ ARGTYPE_HELP, "help", FALSE},
|
|
{ ARGTYPE_NOCVDEBUG, "NoCvDebug", FALSE},
|
|
};
|
|
|
|
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
#define MAX_TOKEN 10
|
|
|
|
//
|
|
// WriteMessage
|
|
//
|
|
// Writes a formatted error message to the console.
|
|
//
|
|
|
|
void
|
|
WriteMessage(
|
|
DWORD dwMessageId,
|
|
...
|
|
)
|
|
{
|
|
|
|
va_list args;
|
|
char MessageBuffer[1024];
|
|
|
|
va_start(args, dwMessageId);
|
|
if (FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, (LPCVOID)
|
|
GetModuleHandle(NULL), dwMessageId, LOCALE_USER_DEFAULT, MessageBuffer,
|
|
sizeof(MessageBuffer), &args))
|
|
printf(MessageBuffer);
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
//
|
|
// WriteMessageWithLastError
|
|
//
|
|
// Writes a formatted error message to the console. This includes a string
|
|
// based on GetLastError()
|
|
//
|
|
|
|
void
|
|
WriteMessageWithLastError(
|
|
DWORD dwMessageId
|
|
)
|
|
{
|
|
|
|
char SystemMessage[256];
|
|
|
|
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
|
LOCALE_USER_DEFAULT, SystemMessage, sizeof(SystemMessage), NULL))
|
|
WriteMessage(dwMessageId, SystemMessage);
|
|
|
|
}
|
|
|
|
//
|
|
// ParseCommandLine
|
|
//
|
|
|
|
BOOL
|
|
ParseCommandLine(
|
|
int argc,
|
|
char* argv[]
|
|
)
|
|
{
|
|
|
|
BOOL fHaveInputFile = FALSE;
|
|
BOOL fHaveOutputFile = FALSE;
|
|
char* pszOption;
|
|
char* pszOptionArg;
|
|
UINT i;
|
|
|
|
if (argc == 1) {
|
|
g_fWantHelp = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
for (argc--, argv++ ; argc ; argc--, argv++) {
|
|
|
|
if (**argv != '/' && **argv != '-') {
|
|
if (fHaveInputFile) {
|
|
WriteMessage(MESSAGE_TOO_MANY_INPUT_FILES);
|
|
return FALSE;
|
|
}
|
|
lstrcpyn(g_szInputFile, *argv, sizeof(g_szInputFile));
|
|
fHaveInputFile = TRUE;
|
|
continue;
|
|
}
|
|
|
|
pszOption = strtok(&(*argv)[1], ":");
|
|
pszOptionArg = strtok(NULL, "");
|
|
|
|
for (i = 0; i < ARRAYSIZE(g_argopts); i++) {
|
|
|
|
if (lstrcmpi(g_argopts[i].pszOption, pszOption) != 0)
|
|
continue;
|
|
|
|
if (g_argopts[i].fExpectArg && pszOptionArg == NULL) {
|
|
WriteMessage(MESSAGE_NO_OPTION_FOR_ARGUMENT, pszOption);
|
|
return FALSE;
|
|
} else if (!g_argopts[i].fExpectArg && pszOptionArg != NULL) {
|
|
WriteMessage(MESSAGE_UNEXPECTED_OPTION_ARGUMENT, pszOption);
|
|
return FALSE;
|
|
}
|
|
|
|
switch (g_argopts[i].type) {
|
|
case ARGTYPE_CPPCMD:
|
|
lstrcpyn(g_szCPPCMD, pszOptionArg, sizeof(g_szCPPCMD));
|
|
break;
|
|
case ARGTYPE_CPPOPT:
|
|
lstrcpyn(g_szCPPOPT, pszOptionArg, sizeof(g_szCPPOPT));
|
|
break;
|
|
case ARGTYPE_LIBCMD:
|
|
lstrcpyn(g_szLIBCMD, pszOptionArg, sizeof(g_szLIBCMD));
|
|
g_fLIBCMDOverride = TRUE;
|
|
break;
|
|
case ARGTYPE_OUT:
|
|
lstrcpyn(g_szOutputFile, pszOptionArg, sizeof(g_szOutputFile));
|
|
fHaveOutputFile = TRUE;
|
|
break;
|
|
case ARGTYPE_HELP:
|
|
g_fWantHelp = TRUE;
|
|
return TRUE;
|
|
case ARGTYPE_LEGO:
|
|
// LEGO support on by default now. Silently ignore the
|
|
// switch.
|
|
break;
|
|
case ARGTYPE_NOCVDEBUG:
|
|
g_fNOCVDEBUG = TRUE;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (i == ARRAYSIZE(g_argopts)) {
|
|
WriteMessage(MESSAGE_UNEXPECTED_OPTION, pszOption);
|
|
}
|
|
|
|
}
|
|
|
|
if (!fHaveInputFile) {
|
|
WriteMessage(MESSAGE_MISSING_INPUT_FILE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!fHaveOutputFile) {
|
|
WriteMessage(MESSAGE_MISSING_OUTPUT_FILE);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// SpawnCommand
|
|
//
|
|
|
|
BOOL
|
|
SpawnCommand(
|
|
char* pszCommandLine
|
|
)
|
|
{
|
|
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFO si;
|
|
DWORD dwWaitResult;
|
|
DWORD dwExitCode;
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
|
|
if (!CreateProcess(NULL, pszCommandLine, NULL, NULL, FALSE, 0, NULL, NULL,
|
|
&si, &pi)) {
|
|
WriteMessageWithLastError(MESSAGE_SPAWN_FAILED);
|
|
return FALSE;
|
|
}
|
|
|
|
// Wait for the command to finish and get its exit code.
|
|
dwWaitResult = WaitForSingleObject(pi.hProcess, INFINITE);
|
|
GetExitCodeProcess(pi.hProcess, &dwExitCode);
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
|
|
if (dwWaitResult != WAIT_OBJECT_0) {
|
|
WriteMessage(MESSAGE_UNEXPECTED_SPAWN_ERROR);
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwExitCode != 0) {
|
|
WriteMessage(MESSAGE_BAD_SPAWN_EXIT_CODE, dwExitCode);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// PreprocessFile
|
|
//
|
|
|
|
BOOL
|
|
PreprocessFile(
|
|
LPSTR pszPreprocessedFile
|
|
)
|
|
{
|
|
|
|
char szCommandLine[MAX_PATH*4];
|
|
char szFullInputPathName[MAX_PATH];
|
|
LPSTR pszFilePart;
|
|
LPSTR pszExtension;
|
|
LPSTR psz;
|
|
int length;
|
|
|
|
WriteMessage(MESSAGE_PREPROCESSING_FILE);
|
|
|
|
lstrcpy(szCommandLine, "\"");
|
|
lstrcat(szCommandLine, g_szCPPCMD);
|
|
lstrcat(szCommandLine, "\" ");
|
|
lstrcat(szCommandLine, g_szCPPOPT);
|
|
lstrcat(szCommandLine, " /nologo /P /EP ");
|
|
lstrcat(szCommandLine, g_szInputFile);
|
|
|
|
if (!SpawnCommand(szCommandLine))
|
|
return FALSE;
|
|
|
|
if (GetFullPathName(g_szInputFile, MAX_PATH, szFullInputPathName,
|
|
&pszFilePart) == 0) {
|
|
//WriteMessage(MESSAGE_UNEXPECTED_PREPROCESS_ERROR);
|
|
return FALSE;
|
|
}
|
|
|
|
for (psz = pszFilePart, pszExtension = NULL; *psz != '\0'; psz++) {
|
|
if (*psz == '.')
|
|
pszExtension = psz;
|
|
}
|
|
|
|
// If there's no extension, then the compiler simply appends ".i" and psz
|
|
// already points at the end of the file.
|
|
if (pszExtension == NULL)
|
|
pszExtension = psz;
|
|
|
|
lstrcpy(pszExtension, ".i");
|
|
|
|
// The preprocessed file is dumped in the current directory, not the
|
|
// directory of the source file.
|
|
GetCurrentDirectory(MAX_PATH, pszPreprocessedFile);
|
|
|
|
// Make sure that the directory ends in a backslash. If called from the
|
|
// root directory, there will be a backslash, but any other directory won't
|
|
// have one!
|
|
length = lstrlen(pszPreprocessedFile);
|
|
if (length && pszPreprocessedFile[length-1] != '\\')
|
|
lstrcat(pszPreprocessedFile, "\\");
|
|
|
|
lstrcat(pszPreprocessedFile, pszFilePart);
|
|
|
|
// Sneak in and copy the base of the input filename. We'll use this base
|
|
// when making the temporary object modules to stick in the output library.
|
|
*pszExtension = '\0';
|
|
lstrcpy(g_szObjectModulePrefix, pszFilePart);
|
|
}
|
|
|
|
//
|
|
// SkipWhitespace
|
|
//
|
|
|
|
void
|
|
SkipWhitespace(
|
|
FILE* pFile
|
|
)
|
|
{
|
|
int ch;
|
|
do {
|
|
ch = fgetc(pFile);
|
|
} while (isspace(ch));
|
|
ungetc(ch, pFile); // CRT ignores if at end of file.
|
|
}
|
|
|
|
//
|
|
// SkipToNextLine
|
|
//
|
|
|
|
void
|
|
SkipToNextLine(
|
|
FILE* pFile
|
|
)
|
|
{
|
|
int ch;
|
|
do {
|
|
ch = fgetc(pFile);
|
|
} while (ch != '\n' && ch != EOF);
|
|
}
|
|
|
|
//
|
|
// ReadSymbol
|
|
//
|
|
// Reads one symbol from the input stream. Returns the length of the symbol.
|
|
// The buffer is assumed to be at least MAX_PATH bytes.
|
|
//
|
|
|
|
int
|
|
ReadSymbol(
|
|
FILE* pFile,
|
|
char* pszSymbol
|
|
)
|
|
{
|
|
int ch;
|
|
int position = 0;
|
|
|
|
SkipWhitespace(pFile);
|
|
ch = fgetc(pFile);
|
|
while (__iscsym(ch)) {
|
|
pszSymbol[position++] = (char) ch;
|
|
if (position >= MAX_PATH)
|
|
return 0;
|
|
ch = fgetc(pFile);
|
|
}
|
|
ungetc(ch, pFile); // CRT ignores if at end of file.
|
|
pszSymbol[position] = '\0';
|
|
return position;
|
|
}
|
|
|
|
//
|
|
// ReadGUID
|
|
//
|
|
// Reads the GUID data from the input stream.
|
|
//
|
|
|
|
int
|
|
ReadGUID(
|
|
FILE* pFile,
|
|
char* pszGUID
|
|
)
|
|
{
|
|
int ch;
|
|
int position = 0;
|
|
|
|
SkipWhitespace(pFile);
|
|
ch = fgetc(pFile);
|
|
while (ch != ';' && ch != EOF) {
|
|
if (!isspace(ch)) {
|
|
pszGUID[position++] = (char) ch;
|
|
if (position >= MAX_PATH)
|
|
return 0;
|
|
}
|
|
ch = fgetc(pFile);
|
|
}
|
|
pszGUID[position] = '\0';
|
|
return position;
|
|
}
|
|
|
|
//
|
|
// MakeTempFile
|
|
//
|
|
|
|
BOOL
|
|
MakeTempFile(
|
|
char* pszTemp,
|
|
char* pszIdentifier,
|
|
char* pszGUID
|
|
)
|
|
{
|
|
|
|
FILE* pOutput;
|
|
char szSourceFile[MAX_PATH*2];
|
|
static UINT tempid;
|
|
|
|
wsprintf(pszTemp, "%s_guid%d", g_szObjectModulePrefix, tempid++);
|
|
lstrcpy(szSourceFile, pszTemp);
|
|
lstrcat(szSourceFile, ".c");
|
|
|
|
if ((pOutput = fopen(szSourceFile, "w")) == NULL)
|
|
return FALSE;
|
|
|
|
fprintf(pOutput, "typedef struct _GUID {\n"
|
|
"\tunsigned long x;\n"
|
|
"\tunsigned short s1;\n"
|
|
"\tunsigned short s2;\n"
|
|
"\tunsigned char c[8];\n"
|
|
"} GUID;\n");
|
|
fprintf(pOutput, "const GUID %s = %s;\n", pszIdentifier, pszGUID);
|
|
fclose(pOutput);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// AddTempFileToLibrary
|
|
//
|
|
|
|
BOOL
|
|
AddTempFileToLibrary(
|
|
char* pszTemp
|
|
)
|
|
{
|
|
|
|
char szCommandLine[MAX_PATH*4];
|
|
char szObjectFile[MAX_PATH*2];
|
|
BOOL fResult;
|
|
static BOOL fFirstTime = TRUE;
|
|
|
|
lstrcpy(szObjectFile, pszTemp);
|
|
lstrcat(szObjectFile, ".obj");
|
|
|
|
// Compile the file with no default library information (/Zl)
|
|
lstrcpy(szCommandLine, "\"");
|
|
lstrcat(szCommandLine, g_szCPPCMD);
|
|
lstrcat(szCommandLine, "\" /nologo /Zl /c /Fo");
|
|
lstrcat(szCommandLine, szObjectFile);
|
|
lstrcat(szCommandLine, " ");
|
|
if( !g_fNOCVDEBUG )
|
|
lstrcat(szCommandLine, "/Z7 ");
|
|
lstrcat(szCommandLine, pszTemp);
|
|
lstrcat(szCommandLine, ".c");
|
|
|
|
if (!SpawnCommand(szCommandLine))
|
|
return FALSE;
|
|
|
|
lstrcpy(szCommandLine, "\"");
|
|
lstrcat(szCommandLine, g_szLIBCMD);
|
|
lstrcat(szCommandLine, "\" /lib /nologo /out:");
|
|
lstrcat(szCommandLine, g_szOutputFile);
|
|
lstrcat(szCommandLine, " ");
|
|
lstrcat(szCommandLine, szObjectFile);
|
|
if (!fFirstTime) {
|
|
lstrcat(szCommandLine, " ");
|
|
lstrcat(szCommandLine, g_szOutputFile);
|
|
}
|
|
|
|
fResult = SpawnCommand(szCommandLine);
|
|
DeleteFile(szObjectFile);
|
|
if (fResult) fFirstTime = FALSE;
|
|
return fResult;
|
|
|
|
}
|
|
|
|
//
|
|
// ProcessFile
|
|
//
|
|
|
|
BOOL
|
|
ProcessFile(
|
|
LPSTR pszFile
|
|
)
|
|
{
|
|
|
|
FILE* pInput;
|
|
char szSymbol[MAX_PATH];
|
|
char szGUID[MAX_PATH];
|
|
char szTempFile[MAX_PATH*2];
|
|
BOOL fResult;
|
|
BOOL fSomethingDone = FALSE;
|
|
|
|
if ((pInput = fopen(pszFile, "r")) == NULL) {
|
|
WriteMessage(MESSAGE_CANNOT_OPEN_INTERMEDIATE_FILE, pszFile);
|
|
return FALSE;
|
|
}
|
|
|
|
while (!feof(pInput)) {
|
|
|
|
if (ReadSymbol(pInput, szSymbol) == 0) {
|
|
SkipToNextLine(pInput);
|
|
continue;
|
|
}
|
|
|
|
// Ignore type qualifiers.
|
|
if (strcmp(szSymbol, "const") == 0 ||
|
|
strcmp(szSymbol, "extern") == 0)
|
|
continue;
|
|
|
|
// Match against any of the GUID aliases we know about.
|
|
if (strcmp(szSymbol, "GUID") != 0 &&
|
|
strcmp(szSymbol, "IID") != 0 &&
|
|
strcmp(szSymbol, "CLSID") != 0 &&
|
|
strcmp(szSymbol, "FLAGID") != 0 &&
|
|
strcmp(szSymbol, "CATID") != 0 &&
|
|
strcmp(szSymbol, "SID") != 0 &&
|
|
strcmp(szSymbol, "LIBID") != 0) {
|
|
SkipToNextLine(pInput);
|
|
continue;
|
|
}
|
|
|
|
if (ReadSymbol(pInput, szSymbol) == 0) {
|
|
SkipToNextLine(pInput);
|
|
continue;
|
|
}
|
|
|
|
SkipWhitespace(pInput);
|
|
|
|
if (fgetc(pInput) != '=') {
|
|
SkipToNextLine(pInput);
|
|
continue;
|
|
}
|
|
|
|
if (ReadGUID(pInput, szGUID) == 0) {
|
|
SkipToNextLine(pInput);
|
|
continue;
|
|
}
|
|
|
|
WriteMessage(MESSAGE_ADDING_IDENTIFIER, szSymbol);
|
|
|
|
if (!MakeTempFile(szTempFile, szSymbol, szGUID)) {
|
|
WriteMessage(MESSAGE_CANNOT_CREATE_INTERMEDIATE_FILE);
|
|
goto error;
|
|
}
|
|
|
|
fResult = AddTempFileToLibrary(szTempFile);
|
|
lstrcat(szTempFile, ".c");
|
|
DeleteFile(szTempFile);
|
|
|
|
if (!fResult)
|
|
goto error;
|
|
|
|
fSomethingDone = TRUE;
|
|
|
|
SkipToNextLine(pInput);
|
|
|
|
}
|
|
|
|
if (!fSomethingDone)
|
|
WriteMessage(MESSAGE_NO_LIBRARY_GENERATED);
|
|
|
|
fResult = TRUE;
|
|
|
|
error:
|
|
fclose(pInput);
|
|
return fResult;
|
|
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
main(
|
|
int argc,
|
|
char* argv[]
|
|
)
|
|
{
|
|
|
|
char szPreprocessedFile[MAX_PATH*2];
|
|
BOOL fResult;
|
|
|
|
// For awhile, support the old syntax until all makefiles have been fixed.
|
|
if (GetEnvironmentVariable("GL_SPAWNSTRING", NULL, 0) != 0) {
|
|
return oldmain(argc, argv);
|
|
}
|
|
|
|
WriteMessage(MESSAGE_BANNER);
|
|
|
|
if (!ParseCommandLine(argc, argv))
|
|
return 1;
|
|
|
|
if (g_fWantHelp) {
|
|
WriteMessage(MESSAGE_HELP);
|
|
return 0;
|
|
}
|
|
|
|
if (GetFileAttributes(g_szOutputFile) != (DWORD) -1) {
|
|
if (!DeleteFile(g_szOutputFile)) {
|
|
WriteMessage(MESSAGE_CANNOT_DELETE, g_szOutputFile);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (!PreprocessFile(szPreprocessedFile))
|
|
return 1;
|
|
|
|
fResult = ProcessFile(szPreprocessedFile);
|
|
DeleteFile(szPreprocessedFile);
|
|
return fResult ? 0 : 1;
|
|
|
|
}
|