412 lines
13 KiB
C++
412 lines
13 KiB
C++
|
|
|
|
#include <string.h>
|
|
#include <iostream>
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <new.h>
|
|
#include "List.h"
|
|
#include "File.h"
|
|
#include "File32.h"
|
|
#include "File64.h"
|
|
#include "Object.h"
|
|
#include "depend.h"
|
|
|
|
List* pQueue;
|
|
List* pDependQueue;
|
|
List* pSearchPath;
|
|
List* pMissingFiles;
|
|
bool bNoisy;
|
|
bool bListDependencies;
|
|
DWORD dwERROR;
|
|
|
|
//
|
|
// Global variables used to get formatted message for this program.
|
|
//
|
|
HMODULE ThisModule = NULL;
|
|
WCHAR Message[4096];
|
|
|
|
// Define a function to be called if new fails to allocate memory.
|
|
//
|
|
int __cdecl MyNewHandler( size_t size )
|
|
{
|
|
|
|
_putws( GetFormattedMessage( ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_MEM_ALLOC_FAILED) );
|
|
// Exit program
|
|
//
|
|
ExitProcess(errOUT_OF_MEMORY);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
usage: depend [/s] [/l] /f:filespec;filespec;... [/d:directory;directory;..]
|
|
If directories are not specififed the Windows search path will be used to look for dependencies
|
|
/s Specifies silent mode.
|
|
filespec - file path and name. Can include wildcards.
|
|
*/
|
|
DWORD _cdecl wmain(int argc,wchar_t *argv[]) {
|
|
|
|
// Set the failure handler for new operator.
|
|
//
|
|
_set_new_handler( MyNewHandler );
|
|
|
|
TCHAR *pszFileName = new TCHAR[256];
|
|
File* pTempFile,*pCurrentFile;
|
|
StringNode* pCurFile;
|
|
char buf[256];
|
|
|
|
dwERROR = 0;
|
|
pSearchPath = 0;
|
|
bNoisy = true;
|
|
bListDependencies = false;
|
|
pQueue = new List();
|
|
pDependQueue = new List();
|
|
pMissingFiles = new List();
|
|
|
|
ThisModule = GetModuleHandle(NULL);
|
|
|
|
//Load the initial files into the queue and load the search path
|
|
if (!ParseCommandLine(argc,argv)) goto CLEANUP;
|
|
|
|
pCurFile = (StringNode*)pQueue->tail;
|
|
|
|
//while the queue isn't empty
|
|
while (pCurFile!=0) {
|
|
WideCharToMultiByte(CP_ACP,0,pCurFile->Data(),-1,buf,256,0,0);
|
|
|
|
//get a file pointer for the current file
|
|
if (!(pCurrentFile = CreateFile(pCurFile->Data()))) {
|
|
|
|
if (bListDependencies) {
|
|
StringNode* s;
|
|
if (s = (StringNode*)pDependQueue->Find(pCurFile->Data())) {
|
|
pDependQueue->Remove(pCurFile->Data());
|
|
}
|
|
}
|
|
|
|
//if there was an error and we are running in silent mode, quit
|
|
if (!bNoisy) goto CLEANUP;
|
|
}
|
|
else { //if we got a file pointer, proceed
|
|
|
|
if (bListDependencies) {
|
|
StringNode* s;
|
|
if (s = (StringNode*)pDependQueue->Find(pCurFile->Data())) {
|
|
pDependQueue->Remove(pCurFile->Data());
|
|
pDependQueue->Add(pCurrentFile);
|
|
}
|
|
}
|
|
|
|
//Check this files dependencies
|
|
pCurrentFile->CheckDependencies();
|
|
|
|
if ((dwERROR)&&(!bNoisy)) goto CLEANUP;
|
|
|
|
//Close the file
|
|
pCurrentFile->CloseFile();
|
|
}
|
|
|
|
//next file
|
|
pCurFile = (StringNode*)pCurFile->prev;
|
|
}
|
|
StringNode* s;
|
|
//if list dependencies is set, print out all dependencies
|
|
if (bListDependencies) {
|
|
pCurrentFile = (File*)pDependQueue->head;
|
|
|
|
//while the queue isn't empty
|
|
while (pCurrentFile!=0) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_DEPENDENCY_HEAD,
|
|
pCurrentFile->Data()) );
|
|
s = (StringNode*)pCurrentFile->dependencies->head;
|
|
while(s) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_FILE_NAME,
|
|
s->Data()) );
|
|
s = (StringNode*)s->next;
|
|
}
|
|
pCurrentFile = (File*)pCurrentFile->next;
|
|
}
|
|
}
|
|
|
|
//print out list of broken files
|
|
pTempFile = (File*)pMissingFiles->head;
|
|
while (pTempFile) {
|
|
if(bNoisy){
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_LIST_OF_BROKEN_FILES,
|
|
pTempFile->Data()) );
|
|
}
|
|
s = (StringNode*)pTempFile->owners->head;
|
|
while(s) {
|
|
if(bNoisy) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_FILE_NAME,
|
|
s->Data()) );
|
|
}
|
|
s = (StringNode*)s->next;
|
|
}
|
|
pTempFile = (File*)pTempFile->next;
|
|
}
|
|
|
|
//Done. Clean up and go home.
|
|
if(bNoisy) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_COMPLETED) );
|
|
}
|
|
CLEANUP:
|
|
|
|
delete [] pszFileName;
|
|
delete pQueue;
|
|
pszFileName = 0;pQueue = 0;
|
|
|
|
return dwERROR;
|
|
}
|
|
|
|
//Given path and filename in 'pathname', fill 'path' with just the path
|
|
void GetPath(TCHAR * pathname,TCHAR* path) {
|
|
|
|
TCHAR* end,t;
|
|
path[0] = '\0';
|
|
|
|
//find last \ in the filename
|
|
end = wcsrchr(pathname,'\\');
|
|
if (!end) return;
|
|
|
|
//copy just the path
|
|
t = end[1];
|
|
end[1] = '\0';
|
|
wcscpy(path,pathname);
|
|
end[1] = t;
|
|
|
|
return;
|
|
}
|
|
|
|
/*Fill queue with the files in the command line and fill searchpath with directories in command line
|
|
usage: depend [/s] /f:filespec;filespec;... [/d:directory;directory;..]
|
|
If directories are not specififed the Windows search path will be used to look for dependencies
|
|
/s Specifies silent mode.
|
|
filespec - file path and name. Can include wildcards.
|
|
*/
|
|
bool ParseCommandLine(int argc,wchar_t* argv[]){
|
|
HANDLE handle;
|
|
int nArg,nFile = 0;
|
|
TCHAR *pszDirectory = new TCHAR[256],*pszFileName = new TCHAR[256],*ptr;
|
|
WIN32_FIND_DATA fileData;
|
|
bool bReturn;
|
|
|
|
if (argc==1) {
|
|
//if there are no arguments, display some kind of help
|
|
if(bNoisy) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_PGM_USAGE) );
|
|
}
|
|
bReturn = false;
|
|
dwERROR = errBAD_ARGUMENTS;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
for (nArg=1;nArg<argc;nArg++) {
|
|
|
|
if (argv[nArg][0] == '/') {
|
|
//if this is the files argument
|
|
if (argv[nArg][1] == 'f') {
|
|
|
|
do {
|
|
ptr = wcschr(argv[nArg]+3,';');
|
|
if (ptr) {
|
|
*ptr = '\0';
|
|
wcscpy(pszFileName,ptr+1);
|
|
} else wcscpy(pszFileName,argv[nArg]+3);
|
|
|
|
//get the first file, put the path in pszDirectory
|
|
handle = FindFirstFile(pszFileName,&fileData);
|
|
GetPath(pszFileName,pszDirectory);
|
|
if (*pszDirectory=='\0') {
|
|
GetCurrentDirectory(256,pszDirectory);
|
|
pszDirectory[wcslen(pszDirectory)+1] = '\0';
|
|
pszDirectory[wcslen(pszDirectory)] = '\\';
|
|
}
|
|
|
|
|
|
//if the file wasn't found, error and quit
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
if(bNoisy) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_ARG_NOT_FOUND,
|
|
argv[nArg]) );
|
|
}
|
|
dwERROR = errFILE_NOT_FOUND;
|
|
bReturn = false;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
//put each file into the queue
|
|
nFile = 1;
|
|
while (nFile) {
|
|
//standardize the name: full path, all lowercase
|
|
wcscpy(pszFileName,pszDirectory);
|
|
wcscat(pszFileName,fileData.cFileName);
|
|
_wcslwr(pszFileName);
|
|
|
|
//add the file to the queue if it's not already there
|
|
if (!pQueue->Find(pszFileName)) pQueue->Add(new StringNode(pszFileName));
|
|
|
|
//if list all dependencies is set, add to dependQueue
|
|
if (bListDependencies)
|
|
if (!pDependQueue->Find(pszFileName))
|
|
pDependQueue->Add(new StringNode(pszFileName));
|
|
|
|
nFile = FindNextFile(handle,&fileData);
|
|
}//end while files
|
|
} while (ptr);
|
|
|
|
} else if (argv[nArg][1] == 'd') {
|
|
|
|
//load directories
|
|
pSearchPath = new List();
|
|
|
|
do {
|
|
ptr = wcschr(argv[nArg]+3,';');
|
|
if (ptr) {
|
|
*ptr = '\0';
|
|
wcscpy(pszDirectory,ptr+1);
|
|
} else wcscpy(pszDirectory,argv[nArg]+3);
|
|
if (pszDirectory[wcslen(pszDirectory)-1]!='\\') {
|
|
pszDirectory[wcslen(pszDirectory)+1] = '\0';
|
|
pszDirectory[wcslen(pszDirectory)] = '\\';
|
|
}
|
|
pSearchPath->Add(new StringNode(pszDirectory));
|
|
} while (ptr);
|
|
|
|
} else
|
|
//if silent mode, turn off noisy flag
|
|
if (argv[nArg][1] == 's') bNoisy = false;
|
|
|
|
else
|
|
//if you want to list the dependencies of all files
|
|
//turn on this flag
|
|
if (argv[nArg][1] == 'l') bListDependencies = true;
|
|
else
|
|
{
|
|
//unrecognized flag
|
|
if(bNoisy) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_BAD_ARGUMENT,
|
|
argv[nArg]) );
|
|
}
|
|
dwERROR = errBAD_ARGUMENTS;
|
|
bReturn = false;
|
|
goto CLEANUP;
|
|
}
|
|
} else {
|
|
//didn't start with a /
|
|
if(bNoisy) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_BAD_ARGUMENT,
|
|
argv[nArg]) );
|
|
}
|
|
dwERROR = errBAD_ARGUMENTS;
|
|
bReturn = false;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
}//end for arguments
|
|
|
|
bReturn = true;
|
|
|
|
CLEANUP:
|
|
|
|
delete[] pszFileName;
|
|
delete[] pszDirectory;
|
|
pszFileName = pszDirectory = 0;
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
//Search for the given file in the given path
|
|
//Arguments:
|
|
//pszFileName - file to look for
|
|
//pszPathName - path to look for it in
|
|
bool SearchPath(TCHAR* pszFileName,TCHAR* pszPathName) {
|
|
StringNode* s;
|
|
WIN32_FIND_DATA buf;
|
|
|
|
if (!pSearchPath) return false;
|
|
|
|
s = (StringNode*)pSearchPath->head;
|
|
|
|
while (s) {
|
|
wcscpy(pszPathName,s->Data());
|
|
wcscat(pszPathName,pszFileName);
|
|
if (FindFirstFile(pszPathName,&buf)!=INVALID_HANDLE_VALUE) return true;
|
|
s = (StringNode*)s->next;
|
|
}
|
|
|
|
pszPathName = 0;
|
|
return false;
|
|
}
|
|
|
|
//Determine what type of file was passed in (16 bit,32,64) and create the appropriate file ptr.
|
|
//pszFileName - file to be loaded
|
|
File* CreateFile(TCHAR* pszFileName) {
|
|
|
|
try {
|
|
return new File32(pszFileName);
|
|
|
|
} catch(int x) {
|
|
if (x == errFILE_LOCKED) return 0;
|
|
try {
|
|
return new File64(pszFileName);
|
|
} catch(int x) {
|
|
if (x == errFILE_LOCKED) return 0;
|
|
if (bNoisy) {
|
|
_putws( GetFormattedMessage(ThisModule,
|
|
FALSE,
|
|
Message,
|
|
sizeof(Message)/sizeof(Message[0]),
|
|
MSG_ERROR_UNRECOGNIZED_FILE_TYPE,
|
|
pszFileName) );
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|