|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
Help.c
Abstract:
Simple minded utility that prints one-line help or spawns other utilities for their help.
Author:
Mark Zbikowski 5/18/2001
Environment:
User Mode
--*/
#include <windows.h>
#include <winnlsp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include "msg.h"
#ifndef SHIFT
#define SHIFT(c,v) {(c)--; (v)++;}
#endif //SHIFT
BOOL PrintString( PWCHAR String ) /*++
Routine Description:
Output a unicode string to the standard output handling redirection
Arguments:
String NUL-terminated UNICODE string for display
Return Value:
TRUE if string was successfully output to STD_OUTPUT_HANDLE FALSE otherwise --*/ { DWORD BytesWritten; DWORD Mode; HANDLE OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
//
// If the output handle is for the console
//
if ((GetFileType( OutputHandle ) & FILE_TYPE_CHAR) && GetConsoleMode( OutputHandle, &Mode) ) {
return WriteConsoleW( OutputHandle, String, wcslen( String ), &BytesWritten, 0);
} else {
BOOL RetValue; int Count = WideCharToMultiByte( GetConsoleOutputCP(), 0, String, -1, 0, 0, 0, 0 ); PCHAR SingleByteString = (PCHAR) malloc( Count );
WideCharToMultiByte( GetConsoleOutputCP( ), 0, String, -1, SingleByteString, Count, 0, 0 );
RetValue = WriteFile( OutputHandle, SingleByteString, Count - 1, &BytesWritten, 0 );
free( SingleByteString );
return RetValue; }
}
PWCHAR GetMsg( ULONG MsgNum, ... ) /*++
Routine Description:
Retrieve, format, and return a message string with all args substituted
Arguments:
MsgNum - the message number to retrieve Optional arguments can be supplied
Return Value:
NULL if the message retrieval/formatting failed Otherwise pointer to the formatted string. --*/ { PTCHAR Buffer = NULL; ULONG msglen; va_list arglist;
va_start( arglist, MsgNum );
msglen = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER , NULL, MsgNum, 0, (LPTSTR) &Buffer, 0, &arglist ); va_end(arglist);
return msglen == 0 ? NULL : Buffer; }
void DisplayMessageError( ULONG MsgNum ) /*++
Routine Description:
Displays a message if we cannot retrieve a message
Arguments:
MsgNum Message number to display
Return Value:
None. --*/ { WCHAR Buffer[32]; PWCHAR MessageString;
_ultow( MsgNum, Buffer, 16 ); MessageString = GetMsg( ERROR_MR_MID_NOT_FOUND, Buffer, L"Application" ); if (MessageString == NULL) { PrintString( L"Unable to get Message-Not-Found message\n" ); } else { PrintString( MessageString ); LocalFree( MessageString ); }
}
BOOL DisplayFullHelp( void ) /*++
Routine Description:
Display the full help set. This assumes all messages in the message file are in the correct order
Arguments:
None.
Return Value:
TRUE if all messages were correctly output FALSE otherwise --*/ { ULONG Message; BOOL RetValue = TRUE;
for (Message = HELP_FIRST_HELP_MESSAGE; RetValue && Message <= HELP_LAST_HELP_MESSAGE; Message++) { PWCHAR MessageString = GetMsg( Message ); if (MessageString == NULL) { DisplayMessageError( Message ); RetValue = FALSE; } else { RetValue = PrintString( MessageString ); LocalFree( MessageString ); } }
return RetValue; }
BOOL DisplaySingleHelp( PWCHAR Command ) /*++
Routine Description:
Display the help appropriate to the specific command
Arguments:
Command NUL-terminated UNICODE string for command
Return Value:
TRUE if help was correctly output FALSE otherwise --*/ { ULONG Message; ULONG Count = wcslen( Command ); PWCHAR MessageString;
//
// Walk through the messages one by one and determine which
// one has the specified command as the prefix.
//
for (Message = HELP_FIRST_COMMAND_HELP_MESSAGE; Message <= HELP_LAST_HELP_MESSAGE; Message++) {
MessageString = GetMsg( Message ); if (MessageString == NULL) { DisplayMessageError( Message ); return FALSE; } else {
if (!_wcsnicmp( Command, MessageString, Count ) && MessageString[Count] == L' ') {
//
// We've found a match. Let the command
// display it's own help
//
WCHAR CommandString[MAX_PATH];
wcscpy( CommandString, Command ); wcscat( CommandString, L" /?" ); _wsystem( CommandString );
LocalFree( MessageString ); return TRUE; } LocalFree( MessageString ); } }
MessageString = GetMsg( HELP_NOT_FOUND_MESSAGE, Command );
if (MessageString == NULL) { DisplayMessageError( Message ); return FALSE; } PrintString( MessageString ); LocalFree( MessageString );
return FALSE; }
//
// HELP with no arguments will display a series of one-line help summaries
// for a variety of tools.
//
// HELP with a single argument will walk through the list of tools it knows
// about and attempt to match the tool against the argument. If one is found,
// the tool is executed with the /? switch and then the tool displays more
// detailed help.
//
INT __cdecl wmain( INT argc, PWSTR argv[] ) /*++
Routine Description:
Source entry point for the
Arguments:
argc - The argument count. argv - string arguments, the first being the name of the executable and the remainder being parameters, only a single one is allowed.
Return Value:
INT - Return Status: 0 if help was successfully displayed 1 otherwise --*/
{ PWSTR ProgramName = argv[0]; PWSTR HelpString; BOOL RetValue; //
// Set up all the various international stuff
//
setlocale( LC_ALL, ".OCP" ) ; SetThreadUILanguage( 0 ); //
// Get past the name of the program
//
SHIFT( argc, argv );
//
// No arguments means a quick blurt of all the messages
//
if (argc == 0) { return DisplayFullHelp( ); }
//
// A single argument is looked up in the message set and
// that command is executed
//
if (argc == 1 && wcscmp( argv[0], L"/?" )) { return DisplaySingleHelp( argv[0] ); }
//
// More than one argument was supplied. This is an error
//
HelpString = GetMsg( HELP_USAGE_MESSAGE, ProgramName ); if (HelpString == NULL) { PrintString( L"Unable to display usage message\n" ); return 1; }
RetValue = PrintString( HelpString );
LocalFree( HelpString );
return RetValue; }
|