/*++ Copyright (c) Microsoft Corporation. All rights reserved. For Internal use only! Module Name: INFSCAN globals.cpp Abstract: Global functions (ie, not part of any class) History: Created July 2001 - JamieHun --*/ #include "precomp.h" #pragma hdrstop #include #include int __cdecl my_new_handler(size_t) { throw std::bad_alloc(); return 0; } int __cdecl main(int argc,char *argv[]) /*++ Routine Description: Main point of entry Defer to GlobalScan::ParseArgs and GlobalScan::Scan Arguments: argc - # of arguments passed on command line argv - arguments passed on command line Return Value: 0 on success 1 no files 2 bad usage 3 fatal error (out of memory) stdout -- scan errors stderr -- trace/fatal errors --*/ { int res; _PNH _old_new_handler = _set_new_handler(my_new_handler); int _old_new_mode = _set_new_mode(1); try { GlobalScan scanner; res = scanner.ParseArgs(argc,argv); if(res != 0) { return res; } res = scanner.Scan(); } catch(bad_alloc &) { res = 3; } if(res == 3) { fprintf(stderr,"Out of memory!\n"); } _set_new_mode(_old_new_mode); _set_new_handler(_old_new_handler); return res; } void FormatToStream(FILE * stream,DWORD fmt,DWORD flags,...) /*++ Routine Description: Format text to stream using a particular msg-id fmt Used for displaying localizable messages Arguments: stream - file stream to output to, stdout or stderr fmt - message id ... - parameters %1... Return Value: none --*/ { va_list arglist; LPTSTR locbuffer = NULL; DWORD count; va_start(arglist, flags); count = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ALLOCATE_BUFFER|flags, NULL, fmt, 0, // LANGID (LPTSTR) &locbuffer, 0, // minimum size of buffer (flags & FORMAT_MESSAGE_ARGUMENT_ARRAY) ? reinterpret_cast(va_arg(arglist,DWORD_PTR*)) : &arglist); if(locbuffer) { if(count) { int c; int back = 0; while(((c = *CharPrev(locbuffer,locbuffer+count)) == TEXT('\r')) || (c == TEXT('\n'))) { count--; back++; } if(back) { locbuffer[count++] = TEXT('\n'); locbuffer[count] = TEXT('\0'); } _fputts(locbuffer,stream); } LocalFree(locbuffer); } } PTSTR CopyString(PCTSTR arg, int extra) /*++ Routine Description: Copy a string into a newly allocated buffer Arguments: arg - string to copy extra - extra characters to allow for Return Value: TCHAR[] buffer, delete with "delete []" --*/ { int max = _tcslen(arg)+1; PTSTR chr = new TCHAR[max+extra]; // may throw bad_alloc memcpy(chr,arg,max*sizeof(TCHAR)); return chr; } #ifdef UNICODE PTSTR CopyString(PCSTR arg, int extra) /*++ Routine Description: Copy a string into a newly allocated buffer Converting from ANSI to UNICODE Arguments: arg - string to copy extra - extra characters to allow for Return Value: TCHAR[] buffer, delete with "delete []" --*/ { int max = strlen(arg)+1; PTSTR chr = new TCHAR[max+extra]; // may throw bad_alloc if(!MultiByteToWideChar(CP_ACP,0,arg,max,chr,max)) { delete [] chr; return NULL; } return chr; } #else PTSTR CopyString(PCWSTR arg, int extra) /*++ Routine Description: Copy a string into a newly allocated buffer Converting from UNICODE to ANSI Arguments: arg - string to copy extra - extra characters to allow for Return Value: TCHAR[] buffer, delete with "delete []" --*/ { #error CopyString(PCWSTR arg,int extra) } #endif int GetFullPathName(const SafeString & given,SafeString & target) /*++ Routine Description: Obtain full pathname Arguments: given - path to convert target - full pathname on success, same as given on error Return Value: 0 on success, !=0 on failure --*/ { DWORD len = GetFullPathName(given.c_str(),0,NULL,NULL); if(len == 0) { if(&target != &given) { target = given; } return -1; } PTSTR chr = new TCHAR[len]; if(!chr) { if(&target != &given) { target = given; } return -1; } DWORD alen = GetFullPathName(given.c_str(),len,chr,NULL); if((alen == 0) || (alen>len)) { if(&target != &given) { target = given; } delete [] chr; return -1; } target = chr; delete [] chr; return 0; } SafeString PathConcat(const SafeString & path,const SafeString & tail) /*++ Routine Description: Combine path and tail, returning newly combined string inserts/removes path seperator if needed Arguments: path - first part tail - last part Return Value: appended path --*/ { if(!path.length()) { return tail; } if(!tail.length()) { return path; } PCTSTR path_p = path.c_str(); int path_l = path.length(); int c = *CharPrev(path_p,path_p+path_l); bool addslash = false; bool takeslash = false; if((c != TEXT('\\')) && (c != TEXT('/'))) { addslash = true; } c = tail[0]; if((c == TEXT('\\')) || (c == TEXT('/'))) { if(addslash) { return path+tail; } else { return path+tail.substr(1); } } else { if(addslash) { return path+SafeString(TEXT("\\"))+tail; } else { return path+tail; } } } VOID Usage(VOID) /*++ Routine Description: Help information Arguments: Return Value: --*/ { _tprintf(TEXT("Usage: INFSCAN [/B ] [/C ] [/D] [/E ] [/F ] [/G] [/I] {/N } {/O } [/P] [Q ] [/R] [/S ] [/T ] [/V ] [/W ] [/X ] [/Y] [/Z] [SourcePath]\n\n")); _tprintf(TEXT("Options:\n\n")); _tprintf(TEXT("/B (build special) Filter /E based on a list of \"unchanged\" files\n")); _tprintf(TEXT(" variation /B1 - based on copied files only\n")); _tprintf(TEXT(" variation /B2 - based on INF files only\n")); _tprintf(TEXT("/C Create INF filter/report based on errors\n")); _tprintf(TEXT("/D Determine non-driver installation sections\n")); _tprintf(TEXT("/E Create a DeviceToInf filter INF\n")); _tprintf(TEXT("/F Filter based on INF: FilterInfPath\n")); _tprintf(TEXT("/G Generate Pnfs first (see also /Z)\n")); _tprintf(TEXT("/I Ignore errors (for when generating file list)\n")); _tprintf(TEXT("/N Specify single INF name (/N may be used multiple times)\n")); _tprintf(TEXT("/O Specify an override directory (/O may be used multiple times and parsed in order)\n")); _tprintf(TEXT("/P Pedantic mode (show potential problems too)\n")); _tprintf(TEXT("/Q Source+Target copied files list (filtered by layout.inf) see also /S\n")); _tprintf(TEXT("/R Trace (list all INF's)\n")); _tprintf(TEXT("/S Source copied files list (filtered by layout.inf) see also /Q\n")); _tprintf(TEXT("/T Specify number of threads to use\n")); _tprintf(TEXT("/V Version (eg NTx86.5.1)\n")); _tprintf(TEXT("/W List of files to include (alternative to /N)\n")); _tprintf(TEXT("/X List of files to exclude (same format as /W) overrides later includes\n")); _tprintf(TEXT("/Y Don't check per-inf [SourceDisksFiles*]\n")); _tprintf(TEXT("/Z Generate Pnfs and quit (see also /G)\n")); _tprintf(TEXT("/? or /H Display brief usage message\n")); } bool MyGetStringField(PINFCONTEXT Context,DWORD FieldIndex,SafeString & result,bool downcase) /*++ Routine Description: Get a string field from an INF downcase it if flag indicates it needs to be (typical case) Arguments: Context - from SetupFindFirstLine/SetupFindNextLine etc FieldIndex - 0 for key, 1-n for parameter result - string obtained downcase - true (typical) to return result as lower-case Return Value: TRUE if success (result modified), FALSE otherwise (result left untouched) --*/ { TCHAR Buf[MAX_INF_STRING_LENGTH]; if(SetupGetStringField(Context,FieldIndex,Buf,MAX_INF_STRING_LENGTH,NULL)) { if(downcase) { _tcslwr(Buf); } result = Buf; return true; } else { // // leave result as is, allowing default capability // return false; } } SafeString QuoteIt(const SafeString & val) /*++ Routine Description: Quote a string in such a way that it will be correctly parsed by SetupAPI Arguments: val - unquoted string Return Value: quoted string --*/ { if(val.empty()) { // // don't quote empty string // return val; } basic_ostringstream result; result << TEXT("\""); LPCTSTR p = val.c_str(); LPCTSTR q; while((q = wcsstr(p,TEXT("%\""))) != NULL) { TCHAR c = *q; q++; // include the special char result << SafeString(p,q-p) << c; // write what we have so far, double up the special char p = q; } result << p << TEXT("\""); return result.str(); } int GeneratePnf(const SafeString & pnf) /*++ Routine Description: Generate a single PNF Arguments: none Return Value: 0 on success --*/ { HINF hInf; hInf = SetupOpenInfFile(pnf.c_str(), NULL, INF_STYLE_WIN4 | INF_STYLE_CACHE_ENABLE, NULL ); if(hInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInf); } return 0; } void Write(HANDLE hFile,const SafeStringW & str) /*++ Routine Description: Write a string to specified file, converting UNICODE to ANSI Arguments: NONE Return Value: 0 on success --*/ { int len = WideCharToMultiByte(CP_ACP,0,str.c_str(),str.length(),NULL,0,NULL,NULL); if(!len) { return; } LPSTR buf = new CHAR[len]; if(!buf) { return; } int nlen = WideCharToMultiByte(CP_ACP,0,str.c_str(),str.length(),buf,len,NULL,NULL); if(!nlen) { delete [] buf; return; } DWORD written; BOOL f = WriteFile(hFile,buf,len,&written,NULL); delete [] buf; } void Write(HANDLE hFile,const SafeStringA & str) /*++ Routine Description: Write a string to specified file as-is Arguments: NONE Return Value: 0 on success --*/ { DWORD written; BOOL f = WriteFile(hFile,str.c_str(),str.length(),&written,NULL); }