442 lines
6.9 KiB
C++
442 lines
6.9 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Chcp
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Chcpo is a DOS5-Compatible codepage utility
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Ramon Juan San Andres (ramonsa) 01-May-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ulib.hxx"
|
|||
|
#include "arg.hxx"
|
|||
|
#include "stream.hxx"
|
|||
|
#include "smsg.hxx"
|
|||
|
#include "wstring.hxx"
|
|||
|
#include "rtmsg.h"
|
|||
|
#include "chcp.hxx"
|
|||
|
|
|||
|
|
|||
|
VOID __cdecl
|
|||
|
main (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Main function of the Chcp utility
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Initialize stuff
|
|||
|
//
|
|||
|
DEFINE_CLASS_DESCRIPTOR( CHCP );
|
|||
|
|
|||
|
{
|
|||
|
CHCP Chcp;
|
|||
|
|
|||
|
if ( Chcp.Initialize() ) {
|
|||
|
|
|||
|
Chcp.Chcp();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DEFINE_CONSTRUCTOR( CHCP, PROGRAM );
|
|||
|
|
|||
|
|
|||
|
|
|||
|
CHCP::~CHCP (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Destructs a CHCP object
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CHCP::Initialize (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initializes a CHCP object
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if initialized.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Initialize program object
|
|||
|
//
|
|||
|
if ( PROGRAM::Initialize( MSG_CHCP_USAGE ) &&
|
|||
|
_Screen.Initialize( )
|
|||
|
|
|||
|
) {
|
|||
|
|
|||
|
_SetCodePage = FALSE;
|
|||
|
_CodePage = 0;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CHCP::Chcp (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Does the Chcp thing.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ValidateVersion();
|
|||
|
|
|||
|
if ( ParseArguments() ) {
|
|||
|
|
|||
|
|
|||
|
if ( _SetCodePage ) {
|
|||
|
|
|||
|
//
|
|||
|
// Set the code page
|
|||
|
//
|
|||
|
if ( !SetCodePage() ) {
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Display current code page
|
|||
|
//
|
|||
|
if ( !DisplayCodePage() ) {
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExitProgram( EXIT_NORMAL );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CHCP::DisplayCodePage (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Displays the active code page
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if success, FALSE if syntax error.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
DisplayMessage(
|
|||
|
MSG_CHCP_ACTIVE_CODEPAGE,
|
|||
|
NORMAL_MESSAGE, "%d",
|
|||
|
_Screen.QueryCodePage( )
|
|||
|
);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CHCP::ParseArguments (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Parses arguments
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if success, FALSE if syntax error.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ARGUMENT_LEXEMIZER ArgLex;
|
|||
|
ARRAY LexArray;
|
|||
|
ARRAY ArgArray;
|
|||
|
|
|||
|
STRING_ARGUMENT ProgramNameArgument;
|
|||
|
LONG_ARGUMENT CodePageArgument;
|
|||
|
FLAG_ARGUMENT UsageArgument;
|
|||
|
|
|||
|
|
|||
|
if ( !ArgArray.Initialize() ||
|
|||
|
!LexArray.Initialize() ||
|
|||
|
!ArgLex.Initialize( &LexArray )
|
|||
|
) {
|
|||
|
|
|||
|
DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
if ( !ProgramNameArgument.Initialize( "*" ) ||
|
|||
|
!UsageArgument.Initialize( "/?" ) ||
|
|||
|
!CodePageArgument.Initialize( "*" )
|
|||
|
) {
|
|||
|
|
|||
|
DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
if ( !ArgArray.Put( &ProgramNameArgument ) ||
|
|||
|
!ArgArray.Put( &UsageArgument ) ||
|
|||
|
!ArgArray.Put( &CodePageArgument )
|
|||
|
) {
|
|||
|
|
|||
|
DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set up the defaults
|
|||
|
//
|
|||
|
ArgLex.PutSwitches( "/" );
|
|||
|
ArgLex.SetCaseSensitive( FALSE );
|
|||
|
|
|||
|
|
|||
|
if ( !ArgLex.PrepareToParse() ) {
|
|||
|
|
|||
|
DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
}
|
|||
|
|
|||
|
if ( !ArgLex.DoParsing( &ArgArray ) ) {
|
|||
|
|
|||
|
DisplayMessage( MSG_CHCP_INVALID_PARAMETER, ERROR_MESSAGE, "%W", ArgLex.QueryInvalidArgument() );
|
|||
|
ExitProgram( EXIT_ERROR );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Display Help if requested
|
|||
|
//
|
|||
|
if ( UsageArgument.IsValueSet() ) {
|
|||
|
|
|||
|
DisplayMessage( MSG_CHCP_USAGE, NORMAL_MESSAGE );
|
|||
|
ExitProgram( EXIT_NORMAL );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( CodePageArgument.IsValueSet() ) {
|
|||
|
|
|||
|
_SetCodePage = TRUE;
|
|||
|
_CodePage = (DWORD)CodePageArgument.QueryLong();
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
_SetCodePage = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
inline bool IsFarEastCodePage(UINT cp)
|
|||
|
{
|
|||
|
return cp == 932 || cp == 949 || cp == 936 || cp == 950;
|
|||
|
}
|
|||
|
|
|||
|
inline bool IsFarEastLocale(LANGID langid)
|
|||
|
{
|
|||
|
// Accepts primay langid only
|
|||
|
return langid == LANG_JAPANESE || langid == LANG_KOREAN || langid == LANG_CHINESE;
|
|||
|
}
|
|||
|
|
|||
|
inline bool IsFarEastSystemLocale()
|
|||
|
{
|
|||
|
return IsFarEastLocale(PRIMARYLANGID(GetSystemDefaultLangID()));
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CHCP::SetCodePage (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Sets the active code page
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if success, FALSE if syntax error.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UINT OldCP = _Screen.QueryCodePage( );
|
|||
|
|
|||
|
if (IsFarEastSystemLocale() &&
|
|||
|
(IsFarEastCodePage(_CodePage) || IsFarEastCodePage(OldCP)) &&
|
|||
|
_CodePage != OldCP) {
|
|||
|
/*
|
|||
|
* This CLS function is needed only if it's FE.
|
|||
|
*/
|
|||
|
_Screen.MoveCursorTo(0, 0);
|
|||
|
_Screen.EraseScreenAndResetAttribute();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if ( _Screen.SetOutputCodePage( _CodePage ) ) {
|
|||
|
if (_Screen.SetCodePage( _CodePage ) ) {
|
|||
|
|
|||
|
// Comment from NT4J:
|
|||
|
// Since FormatMessage checks the current TEB's locale, and the Locale for
|
|||
|
// CHCP is initialized when the message class is initialized, the TEB has to
|
|||
|
// be updated after the code page is changed successfully. All other code
|
|||
|
// pages other than JP and US are ignored.
|
|||
|
|
|||
|
if (IsFarEastSystemLocale()) {
|
|||
|
LANGID LangId;
|
|||
|
|
|||
|
switch (_CodePage) {
|
|||
|
case 932:
|
|||
|
LangId = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
|
|||
|
break;
|
|||
|
case 949:
|
|||
|
LangId = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
|
|||
|
break;
|
|||
|
case 936:
|
|||
|
LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
|
|||
|
break;
|
|||
|
case 950:
|
|||
|
LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
|
|||
|
break;
|
|||
|
default:
|
|||
|
LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
SetThreadLocale(MAKELCID(LangId, SORT_DEFAULT));
|
|||
|
}
|
|||
|
|
|||
|
return DisplayCodePage( );
|
|||
|
} else {
|
|||
|
// SetOutputCodePage failed.
|
|||
|
// Restore the privous input code page
|
|||
|
_Screen.SetOutputCodePage( OldCP );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Was unable to set the given code page
|
|||
|
DisplayMessage( MSG_CHCP_INVALID_CODEPAGE, ERROR_MESSAGE );
|
|||
|
return FALSE;
|
|||
|
}
|