Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1182 lines
26 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
pch.c
Abstract:
This file is a tool for converting an existing slm project to build
using pre-compiled header files.
Author:
Wesley Witt (wesw) 1-Oct-1993
Environment:
User Mode
--*/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _tagFILEINFO {
HANDLE hFile;
HANDLE hMap;
LPSTR fptr;
CHAR fname[MAX_PATH];
} FILEINFO, *PFILEINFO;
char hfiles[5000][20];
DWORD idx;
CHAR ipath[100][MAX_PATH];
DWORD cipath;
#define BAD_FILE (DWORD)-1
//
// options flags
//
BOOL fModifySource;
BOOL fVerbose;
BOOL fGenerateHeader;
BOOL fRecurseDirs;
BOOL fDoReadOnly;
BOOL fCheckOut;
BOOL fModifySlmSourcesFile;
DWORD LinenoLimit = 0xefffffff;
CHAR szHeaderFileName[MAX_PATH];
CHAR szRecurseDir[MAX_PATH];
VOID
GetCommandLineArgs(
VOID
);
BOOL
MapInputFile (
PFILEINFO lpfi
);
VOID
UnMapFile(
PFILEINFO lpfi
);
VOID
FindHeaderFiles(
LPSTR SourceFileName
);
VOID
ChangeSourceFile(
LPSTR fname
);
VOID
GenerateHeaderFile(
LPSTR fname
);
VOID
ProcessFilesInTree(
LPSTR RootPath,
DWORD Action
);
VOID
Usage(
VOID
);
BOOL
IsValidSourceFile(
LPSTR fname
);
BOOL
CheckOutSourceFile(
LPSTR fname
);
VOID
ChangeSlmSourcesFile(
VOID
);
DWORD
FindHeaderFile(
LPSTR HeaderFileName
);
VOID
GetIncludePath(
VOID
);
void _cdecl
main( void )
/*++
Routine Description:
This is the entry point for the pch tool.
Arguments:
None.
Return Value:
None.
--*/
{
GetCommandLineArgs();
GetIncludePath();
if (fVerbose) {
printf("processing source files\n");
}
ProcessFilesInTree( szRecurseDir, 1 );
if (fGenerateHeader) {
if (fVerbose) {
printf("creating headerfile: %s\n", szHeaderFileName);
}
GenerateHeaderFile( szHeaderFileName );
}
if (fModifySource) {
if (fVerbose) {
printf("modifying source files\n");
}
ProcessFilesInTree( szRecurseDir, 2 );
}
if (fModifySlmSourcesFile) {
ChangeSlmSourcesFile();
}
}
BOOL
MapInputFile (
PFILEINFO lpfi
)
/*++
Routine Description:
Opens and maps a file or reading only.
Arguments:
lpfi - pointer to a FILEINFO structure, only the file name
need be filled in before calling.
Return Value:
None.
--*/
{
lpfi->hFile = CreateFile( lpfi->fname,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (lpfi->hFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
lpfi->hMap = CreateFileMapping( lpfi->hFile,
NULL,
PAGE_READONLY,
0,
0,
NULL
);
if (lpfi->hMap == INVALID_HANDLE_VALUE) {
CloseHandle( lpfi->hFile );
return FALSE;
}
lpfi->fptr = MapViewOfFile( lpfi->hMap, FILE_MAP_READ, 0, 0, 0 );
if (lpfi->fptr == NULL) {
CloseHandle( lpfi->hFile );
CloseHandle( lpfi->hMap );
return FALSE;
}
return TRUE;
}
BOOL
MapOutputFile (
PFILEINFO lpfi,
DWORD fsize
)
/*++
Routine Description:
Opens and maps a file or reading and writing.
Arguments:
lpfi - pointer to a FILEINFO structure, only the file name
need be filled in before calling.
Return Value:
None.
--*/
{
lpfi->hFile = CreateFile( lpfi->fname,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
0,
NULL
);
if (lpfi->hFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
lpfi->hMap = CreateFileMapping( lpfi->hFile,
NULL,
PAGE_READWRITE,
0,
fsize,
NULL
);
if (lpfi->hMap == INVALID_HANDLE_VALUE) {
CloseHandle( lpfi->hFile );
return FALSE;
}
lpfi->fptr = MapViewOfFile( lpfi->hMap, FILE_MAP_WRITE, 0, 0, 0 );
if (lpfi->fptr == NULL) {
CloseHandle( lpfi->hFile );
CloseHandle( lpfi->hMap );
return FALSE;
}
return TRUE;
}
VOID
UnMapFile(
PFILEINFO lpfi
)
/*++
Routine Description:
Closes all handles and views for an opened/mapped file.
Arguments:
lpfi - pointer to a FILEINFO structure
Return Value:
None.
--*/
{
CloseHandle( lpfi->hFile );
CloseHandle( lpfi->hMap );
UnmapViewOfFile( lpfi->fptr );
}
VOID
FindHeaderFiles(
LPSTR SourceFileName
)
/*++
Routine Description:
Scans a source file an locates all header files used by the
source file. The names are stored in a global array.
Arguments:
SourceFileName - name of source file to begin search
Return Value:
None.
--*/
{
LPSTR p;
DWORD i;
CHAR fname[MAX_PATH];
CHAR drive[_MAX_FNAME];
CHAR dir[_MAX_DIR];
CHAR name[_MAX_FNAME];
CHAR ext[_MAX_EXT];
CHAR buf[MAX_PATH];
FILEINFO fi;
strcpy( fi.fname, SourceFileName );
MapInputFile( &fi );
p = fi.fptr;
while (p && *p) {
if (*p == '#') {
if (strncmp(p,"#include",8)==0) {
p += 8;
while (p && *p==' ') {
p++;
}
p++;
i = 0;
while (*p != '>' && *p != '"') {
fname[i] = *p;
p++;
i++;
}
fname[i] = '\0';
if (IsValidSourceFile(fname)) {
_splitpath( SourceFileName, drive, dir, name, ext );
sprintf( buf, "%s%s", drive, dir );
_splitpath( fname, drive, dir, name, ext );
strcat( buf, dir );
sprintf( fname, "%s%s", name, ext );
strcat( buf, fname );
_fullpath( fname, buf, sizeof(fname) );
FindHeaderFiles( fname );
} else {
for (i=0; i<idx; i++) {
if (stricmp(hfiles[i],fname)==0) {
break;
}
}
if (i == idx) {
strcpy(hfiles[idx],fname);
idx++;
}
}
}
}
p++;
}
UnMapFile( &fi );
}
VOID
ChangeSourceFile(
LPSTR SourceFileName
)
/*++
Routine Description:
Scans a source file and locates all '#includes', removes all
'#includes', adds a single '#include' for the precompiled header
file. If a source file is included the '#include' is preserved.
Arguments:
SourceFileName - name of source file to change
Return Value:
None.
--*/
{
LPSTR p;
LPSTR p1;
LPSTR po;
FILEINFO fi;
FILEINFO fiout;
DWORD dwHigh;
DWORD i;
CHAR fname[MAX_PATH];
CHAR buf[MAX_PATH];
DWORD lineno = 0;
if (fCheckOut) {
CheckOutSourceFile( SourceFileName );
}
strcpy( fi.fname, SourceFileName );
MapInputFile( &fi );
strcpy( fiout.fname, "temp.xxx" );
MapOutputFile( &fiout, GetFileSize( fi.hFile, &dwHigh ) + 1024 );
p = fi.fptr;
po = fiout.fptr;
while (p && *p) {
if (*p == '#') {
if (strncmp(p,"#include",8)==0) {
p1 = p;
p1 += 8;
while (p1 && *p1==' ') {
p1++;
}
p1++;
i = 0;
while (*p1 != '>' && *p1 != '"') {
fname[i] = *p1;
p1++;
i++;
}
fname[i] = '\0';
if (IsValidSourceFile(fname)) {
po = fiout.fptr;
p = fi.fptr;
sprintf(po,"#include \"%s\"\r\n", szHeaderFileName);
po += strlen(po);
strcpy(po,"#pragma hdrstop\r\n\r\n");
po += strlen(po);
while (p && *p) {
*po++ = *p++;
}
SetFilePointer( fiout.hFile, po-fiout.fptr, NULL, FILE_BEGIN );
SetEndOfFile( fiout.hFile );
UnMapFile( &fiout );
UnMapFile( &fi );
DeleteFile( SourceFileName );
MoveFile( "temp.xxx", SourceFileName );
_fullpath( buf, fname, sizeof(buf) );
if (fCheckOut) {
CheckOutSourceFile( buf );
}
strcpy( fi.fname, buf );
MapInputFile( &fi );
strcpy( fiout.fname, "temp.xxx" );
MapOutputFile( &fiout, GetFileSize( fi.hFile, &dwHigh ) + 1024 );
p = fi.fptr;
po = fiout.fptr;
while (p && *p) {
if (*p == '#') {
if (lineno < LinenoLimit && strncmp(p,"#include",8)==0) {
while( *p != '\n') {
p++;
}
p++;
continue;
}
}
if (*p == '\n') {
lineno++;
}
*po++ = *p++;
}
SetFilePointer( fiout.hFile, po-fiout.fptr, NULL, FILE_BEGIN );
SetEndOfFile( fiout.hFile );
UnMapFile( &fiout );
UnMapFile( &fi );
DeleteFile( buf );
MoveFile( "temp.xxx", buf );
return;
}
sprintf(po,"#include \"%s\"\r\n", szHeaderFileName);
po += strlen(po);
strcpy(po,"#pragma hdrstop\r\n");
po += strlen(po);
while( *p != '\n') {
p++;
}
p++;
break;
}
}
if (*p == '\n') {
lineno++;
}
*po++ = *p++;
}
while (p && *p) {
if (*p == '#') {
if (lineno < LinenoLimit && strncmp(p,"#include",8)==0) {
while( *p != '\n') {
p++;
}
p++;
continue;
}
}
if (*p == '\n') {
lineno++;
}
*po++ = *p++;
}
SetFilePointer( fiout.hFile, po-fiout.fptr, NULL, FILE_BEGIN );
SetEndOfFile( fiout.hFile );
UnMapFile( &fiout );
UnMapFile( &fi );
DeleteFile( SourceFileName );
MoveFile( "temp.xxx", SourceFileName );
}
VOID
GenerateHeaderFile(
LPSTR fname
)
/*++
Routine Description:
Generates a header file that is comprised of the union of all
header files used in the project that has been scanned. Each header
file is verified to be a 'public' header file or a 'private'
header file. Depending on the determination a different deliminator
is used in the '#include' statement.
Arguments:
fname - name of the precompiled header file to generate
Return Value:
None.
--*/
{
LPSTR p;
DWORD i;
FILEINFO fi;
strcpy( fi.fname, fname );
MapOutputFile( &fi, idx * 1024 );
p = fi.fptr;
for (i=0; i<idx; i++) {
if (FindHeaderFile(hfiles[i]) > 1) {
sprintf( p, "#include \"%s\"\r\n", hfiles[i] );
} else {
sprintf( p, "#include <%s>\r\n", hfiles[i] );
}
p += strlen(p);
}
SetFilePointer( fi.hFile, p-fi.fptr, NULL, FILE_BEGIN );
SetEndOfFile( fi.hFile );
UnMapFile( &fi );
}
VOID
ChangeSlmSourcesFile(
VOID
)
/*++
Routine Description:
Makes all necessary changes to the project's sources file. This is
simply to add the necessary macros for builing with pch files.
Arguments:
None.
Return Value:
None.
--*/
{
#define strout(s) strcpy(p,s); p+=strlen(p)
LPSTR p,p1;
FILEINFO fi;
FILEINFO fiout;
DWORD dwHigh;
DWORD fsize;
DWORD i;
CHAR fname[MAX_PATH];
if (fVerbose) {
printf("modifying slm sources file\n");
}
_fullpath( fname, "sources", sizeof(fname) );
CheckOutSourceFile( fname );
strcpy( fi.fname, "sources" );
MapInputFile( &fi );
fsize = GetFileSize( fi.hFile, &dwHigh );
strcpy( fiout.fname, "temp.xxx" );
MapOutputFile( &fiout, fsize + 1024 );
p1 = fi.fptr;
p = fiout.fptr;
while (p1 && *p1) {
if (*p1 == 0x1a) {
break;
}
if (strncmp(p1,"SOURCES=",8)==0) {
for (i=0; i<8; i++) {
*p++ = *p1++;
}
sprintf(p, "%s ", szHeaderFileName);
p += strlen(p);
}
*p++ = *p1++;
}
_splitpath( szHeaderFileName, NULL, NULL, fname, NULL );
strout( "\r\n" );
// strout( "!IFNDEF NTNOPCH\r\n" );
strout( "PRECOMPILED_INCLUDE=" );
strout( fname );
strout( ".h\r\n" );
strout( "PRECOMPILED_PCH=" );
strout( fname );
strout( ".pch\r\n" );
strout( "PRECOMPILED_OBJ=" );
strout( fname );
strout( ".obj\r\n" );
// strout( "!ENDIF\r\n" );
strout( "\r\n" );
SetFilePointer( fiout.hFile, p-fiout.fptr, NULL, FILE_BEGIN );
SetEndOfFile( fiout.hFile );
UnMapFile( &fiout );
UnMapFile( &fi );
DeleteFile( "sources" );
MoveFile( "temp.xxx", "sources" );
}
VOID
GetCommandLineArgs(
VOID
)
/*++
Routine Description:
Retreives the command line arguments and sets the appropriate
global variables.
Arguments:
None.
Return Value:
None.
--*/
{
char *lpstrCmd = GetCommandLine();
UCHAR ch;
DWORD i = 0;
// skip over program name
do {
ch = *lpstrCmd++;
}
while (ch != ' ' && ch != '\t' && ch != '\0');
// skip over any following white space
while (ch == ' ' || ch == '\t') {
ch = *lpstrCmd++;
}
// process each switch character '-' as encountered
while (ch == '-' || ch == '/') {
ch = tolower(*lpstrCmd++);
// process multiple switch characters as needed
do {
switch (ch) {
case 'h':
// skip whitespace
do {
ch = *lpstrCmd++;
} while (ch == ' ' || ch == '\t');
i=0;
while (ch != ' ' && ch != '\0') {
szHeaderFileName[i++] = ch;
ch = *lpstrCmd++;
}
szHeaderFileName[i] = '\0';
fGenerateHeader = TRUE;
break;
case 'm':
ch = *lpstrCmd++;
fModifySource = TRUE;
break;
case 'r':
// skip whitespace
do {
ch = *lpstrCmd++;
} while (ch == ' ' || ch == '\t');
i=0;
while (ch != ' ' && ch != '\0') {
szRecurseDir[i++] = ch;
ch = *lpstrCmd++;
}
szRecurseDir[i] = '\0';
fRecurseDirs = TRUE;
break;
case 'v':
ch = *lpstrCmd++;
fVerbose = TRUE;
break;
case 'o':
ch = *lpstrCmd++;
fDoReadOnly = TRUE;
break;
case 't':
ch = *lpstrCmd++;
fCheckOut = TRUE;
break;
case 'l':
ch = *lpstrCmd++;
fModifySlmSourcesFile = TRUE;
break;
case 'n':
// skip whitespace
do {
ch = *lpstrCmd++;
} while (ch == ' ' || ch == '\t');
i=0;
while (ch >= '0' && ch <= '9') {
i = i * 10 + ch - '0';
ch = *lpstrCmd++;
}
LinenoLimit = i;
break;
case '?':
Usage();
ch = *lpstrCmd++;
break;
default:
return;
}
} while (ch != ' ' && ch != '\t' && ch != '\0');
while (ch == ' ' || ch == '\t') {
ch = *lpstrCmd++;
}
}
return;
}
VOID
Usage(
VOID
)
/*++
Routine Description:
Prints usage text for this tool.
Arguments:
None.
Return Value:
None.
--*/
{
fprintf( stderr, "Microsoft (R) Windows NT (TM) Version 3.1 PCH\n" );
fprintf( stderr, "Copyright (C) 1993 Microsoft Corp. All rights reserved\n\n" );
fprintf( stderr, "usage: PCH [-?] [-v] [-m] [-o] [-t] [-l] [-n lines][-h headerfile] [-r directory]\n" );
fprintf( stderr, " [-?] display this message\n" );
fprintf( stderr, " [-v] verbose output\n" );
fprintf( stderr, " [-m] modify source files\n" );
fprintf( stderr, " [-o] override readonly\n" );
fprintf( stderr, " [-t] check out if readonly\n" );
fprintf( stderr, " [-l] modify slm sources file\n" );
fprintf( stderr, " [-n lines] limit header file scan to n lines\n" );
fprintf( stderr, " [-h headerfile] - create pch header file\n" );
fprintf( stderr, " [-r directory] - recusively process all source files\n" );
ExitProcess(0);
}
VOID
ProcessFilesInTree(
LPSTR RootPath,
DWORD Action
)
/*++
Routine Description:
Locates all source files for a given tree and performs a requested
action on the source file.
Arguments:
RootPath - Root of the tree to process
Action - Action to perform
1 = Find all header files used by source file
2 = Change the source file to use pch file
Return Value:
None.
--*/
{
#define MAX_DEPTH 32
LPSTR FilePart;
PUCHAR Prefix = "";
CHAR PathBuffer[ MAX_PATH ];
ULONG Depth;
PCHAR PathTail[ MAX_DEPTH ];
PCHAR FindHandle[ MAX_DEPTH ];
LPWIN32_FIND_DATA FindFileData;
UCHAR FindFileBuffer[ MAX_PATH + sizeof( WIN32_FIND_DATA ) ];
CHAR CurrentImageName[ MAX_PATH ];
strcpy( PathBuffer, RootPath );
FindFileData = (LPWIN32_FIND_DATA)FindFileBuffer;
Depth = 0;
while (TRUE) {
startDirectorySearch:
PathTail[ Depth ] = strchr( PathBuffer, '\0' );
if (PathTail[ Depth ] > PathBuffer && PathTail[ Depth ][ -1 ] != '\\') {
*(PathTail[ Depth ])++ = '\\';
}
strcpy( PathTail[ Depth ], "*.*" );
FindHandle[ Depth ] = FindFirstFile( PathBuffer, FindFileData );
if (FindHandle[ Depth ] != INVALID_HANDLE_VALUE) {
do {
if (FindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (strcmp( FindFileData->cFileName, "." ) &&
strcmp( FindFileData->cFileName, ".." ) &&
Depth < MAX_DEPTH
) {
sprintf( PathTail[ Depth ], "%s\\", FindFileData->cFileName );
Depth++;
if (fVerbose) {
printf( "processing dir %s\n", FindFileData->cFileName );
}
goto startDirectorySearch;
}
goto restartDirectorySearch;
} else
if (!IsValidSourceFile( FindFileData->cFileName )) {
goto restartDirectorySearch;
} else
if (FindFileData->dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
if (fCheckOut) {
} else
if (!fDoReadOnly) {
if (fVerbose) {
printf( "skipping %s - readonly file\n", FindFileData->cFileName );
}
goto restartDirectorySearch;
}
}
strcpy( PathTail[ Depth ], FindFileData->cFileName );
if (!GetFullPathName( PathBuffer, sizeof( CurrentImageName ), CurrentImageName, &FilePart )) {
printf( "invalid file name - %s (%u)\n", PathBuffer, GetLastError() );
} else {
if (Action == 1) {
if (fVerbose) {
printf("parsing %s\n", CurrentImageName);
}
FindHeaderFiles( CurrentImageName );
} else
if (Action == 2) {
if (fVerbose) {
printf("modifying %s\n", CurrentImageName);
}
ChangeSourceFile( CurrentImageName );
}
}
restartDirectorySearch:
;
}
while (FindNextFile( FindHandle[ Depth ], FindFileData ));
FindClose( FindHandle[ Depth ] );
if (Depth == 0) {
break;
}
Depth--;
goto restartDirectorySearch;
}
}
return;
}
BOOL
IsValidSourceFile(
LPSTR fname
)
/*++
Routine Description:
Determines if a file name is a source file. The determination is based
on the extension of the file.
Arguments:
fname - name of file
Return Value:
TRUE - file is a source file
FALSE - file is NOT a source file
--*/
{
char ext[20];
_splitpath( fname, NULL, NULL, NULL, ext );
if (_stricmp(ext,".c")==0) {
return TRUE;
} else
if (_stricmp(ext,".cxx")==0) {
return TRUE;
} else
if (_stricmp(ext,".cpp")==0) {
return TRUE;
} else {
return FALSE;
}
}
BOOL
CheckOutSourceFile(
LPSTR fname
)
/*++
Routine Description:
Checks the file out of the SLM project so that it may be changed.
Arguments:
fname - fully qualified file name
Return Value:
TRUE - file was checked ouy
FALSE - file was NOT checked out
--*/
{
CHAR szCmdLine[256];
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD dwExitCode;
CHAR dir[_MAX_DIR];
CHAR name[_MAX_FNAME];
CHAR ext[_MAX_EXT];
if (!(GetFileAttributes( fname ) & FILE_ATTRIBUTE_READONLY)) {
return TRUE;
}
if (fVerbose) {
printf( "checking out %s\n", fname );
}
_splitpath( fname, NULL, dir, name, ext );
sprintf( szCmdLine, "out -f %s%s", name, ext );
GetStartupInfo( &si );
if (!CreateProcess( NULL, szCmdLine, NULL, NULL,
FALSE, 0, NULL, dir, &si, &pi )) {
return FALSE;
}
WaitForSingleObject( pi.hProcess, INFINITE );
if (!GetExitCodeProcess( pi.hProcess, &dwExitCode )) {
return FALSE;
}
if (dwExitCode) {
return FALSE;
}
return TRUE;
}
VOID
GetIncludePath(
VOID
)
/*++
Routine Description:
Gets the include path from the slm sources file.
Arguments:
None.
Return Value:
None.
--*/
{
FILEINFO fi;
LPSTR p;
LPSTR p2;
DWORD i;
DWORD j;
CHAR s[MAX_PATH];
strcpy( fi.fname, "sources" );
MapInputFile( &fi );
p = fi.fptr;
while (p && *p) {
if (strncmp(p,"INCLUDES",8)==0) {
p+=9;
i=0;
while (*p != '\n') {
s[i] = *p;
p++;
i++;
}
s[i] = '\0';
break;
}
p++;
}
UnMapFile( &fi );
strcpy( ipath[0], "\\nt\\public\\sdk\\inc" );
strcpy( ipath[1], "\\nt\\public\\sdk\\inc\\crt" );
strcpy( ipath[2], "." );
if (*s) {
p = p2 = s;
j = 3;
while (*p && *p != '\n') {
if (*p == ';') {
*p = '\0';
strcpy( ipath[j++], p2 );
p2 = p + 1;
}
p++;
}
if (*p != ';') {
*(p-1) = '\0';
strcpy( ipath[j++], p2 );
}
cipath = j;
}
return;
}
DWORD
FindHeaderFile(
LPSTR HeaderFileName
)
/*++
Routine Description:
Gets the path where a header file is located. The file is
searched for in the public directorys, the current directory, and
all paths specified in the slm sources file.
Arguments:
HeaderFileName - name of the header file
Return Value:
Index of the path where the header file is located.
--*/
{
DWORD i;
WIN32_FIND_DATA fd;
HANDLE hfind;
CHAR fname[MAX_PATH];
for (i=0; i<cipath; i++) {
sprintf( fname, "%s\\%s", ipath[i], HeaderFileName );
hfind = FindFirstFile( fname, &fd );
if (hfind != INVALID_HANDLE_VALUE) {
FindClose( hfind );
return i;
}
}
return BAD_FILE;
}