Source code of Windows XP (NT5)
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.

441 lines
6.9 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. Chcp
  5. Abstract:
  6. Chcpo is a DOS5-Compatible codepage utility
  7. Author:
  8. Ramon Juan San Andres (ramonsa) 01-May-1991
  9. Revision History:
  10. --*/
  11. #include "ulib.hxx"
  12. #include "arg.hxx"
  13. #include "stream.hxx"
  14. #include "smsg.hxx"
  15. #include "wstring.hxx"
  16. #include "rtmsg.h"
  17. #include "chcp.hxx"
  18. VOID __cdecl
  19. main (
  20. )
  21. /*++
  22. Routine Description:
  23. Main function of the Chcp utility
  24. Arguments:
  25. None.
  26. Return Value:
  27. None.
  28. Notes:
  29. --*/
  30. {
  31. //
  32. // Initialize stuff
  33. //
  34. DEFINE_CLASS_DESCRIPTOR( CHCP );
  35. {
  36. CHCP Chcp;
  37. if ( Chcp.Initialize() ) {
  38. Chcp.Chcp();
  39. }
  40. }
  41. }
  42. DEFINE_CONSTRUCTOR( CHCP, PROGRAM );
  43. CHCP::~CHCP (
  44. )
  45. /*++
  46. Routine Description:
  47. Destructs a CHCP object
  48. Arguments:
  49. None.
  50. Return Value:
  51. None.
  52. Notes:
  53. --*/
  54. {
  55. }
  56. BOOLEAN
  57. CHCP::Initialize (
  58. )
  59. /*++
  60. Routine Description:
  61. Initializes a CHCP object
  62. Arguments:
  63. None.
  64. Return Value:
  65. TRUE if initialized.
  66. Notes:
  67. --*/
  68. {
  69. //
  70. // Initialize program object
  71. //
  72. if ( PROGRAM::Initialize( MSG_CHCP_USAGE ) &&
  73. _Screen.Initialize( )
  74. ) {
  75. _SetCodePage = FALSE;
  76. _CodePage = 0;
  77. return TRUE;
  78. }
  79. return FALSE;
  80. }
  81. BOOLEAN
  82. CHCP::Chcp (
  83. )
  84. /*++
  85. Routine Description:
  86. Does the Chcp thing.
  87. Arguments:
  88. None.
  89. Return Value:
  90. TRUE.
  91. Notes:
  92. --*/
  93. {
  94. ValidateVersion();
  95. if ( ParseArguments() ) {
  96. if ( _SetCodePage ) {
  97. //
  98. // Set the code page
  99. //
  100. if ( !SetCodePage() ) {
  101. ExitProgram( EXIT_ERROR );
  102. }
  103. } else {
  104. //
  105. // Display current code page
  106. //
  107. if ( !DisplayCodePage() ) {
  108. ExitProgram( EXIT_ERROR );
  109. }
  110. }
  111. ExitProgram( EXIT_NORMAL );
  112. } else {
  113. ExitProgram( EXIT_ERROR );
  114. }
  115. return TRUE;
  116. }
  117. BOOLEAN
  118. CHCP::DisplayCodePage (
  119. )
  120. /*++
  121. Routine Description:
  122. Displays the active code page
  123. Arguments:
  124. None.
  125. Return Value:
  126. TRUE if success, FALSE if syntax error.
  127. Notes:
  128. --*/
  129. {
  130. DisplayMessage(
  131. MSG_CHCP_ACTIVE_CODEPAGE,
  132. NORMAL_MESSAGE, "%d",
  133. _Screen.QueryCodePage( )
  134. );
  135. return TRUE;
  136. }
  137. BOOLEAN
  138. CHCP::ParseArguments (
  139. )
  140. /*++
  141. Routine Description:
  142. Parses arguments
  143. Arguments:
  144. None.
  145. Return Value:
  146. TRUE if success, FALSE if syntax error.
  147. Notes:
  148. --*/
  149. {
  150. ARGUMENT_LEXEMIZER ArgLex;
  151. ARRAY LexArray;
  152. ARRAY ArgArray;
  153. STRING_ARGUMENT ProgramNameArgument;
  154. LONG_ARGUMENT CodePageArgument;
  155. FLAG_ARGUMENT UsageArgument;
  156. if ( !ArgArray.Initialize() ||
  157. !LexArray.Initialize() ||
  158. !ArgLex.Initialize( &LexArray )
  159. ) {
  160. DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
  161. ExitProgram( EXIT_ERROR );
  162. }
  163. if ( !ProgramNameArgument.Initialize( "*" ) ||
  164. !UsageArgument.Initialize( "/?" ) ||
  165. !CodePageArgument.Initialize( "*" )
  166. ) {
  167. DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
  168. ExitProgram( EXIT_ERROR );
  169. }
  170. if ( !ArgArray.Put( &ProgramNameArgument ) ||
  171. !ArgArray.Put( &UsageArgument ) ||
  172. !ArgArray.Put( &CodePageArgument )
  173. ) {
  174. DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
  175. ExitProgram( EXIT_ERROR );
  176. }
  177. //
  178. // Set up the defaults
  179. //
  180. ArgLex.PutSwitches( "/" );
  181. ArgLex.SetCaseSensitive( FALSE );
  182. if ( !ArgLex.PrepareToParse() ) {
  183. DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
  184. ExitProgram( EXIT_ERROR );
  185. }
  186. if ( !ArgLex.DoParsing( &ArgArray ) ) {
  187. DisplayMessage( MSG_CHCP_INVALID_PARAMETER, ERROR_MESSAGE, "%W", ArgLex.QueryInvalidArgument() );
  188. ExitProgram( EXIT_ERROR );
  189. }
  190. //
  191. // Display Help if requested
  192. //
  193. if ( UsageArgument.IsValueSet() ) {
  194. DisplayMessage( MSG_CHCP_USAGE, NORMAL_MESSAGE );
  195. ExitProgram( EXIT_NORMAL );
  196. }
  197. if ( CodePageArgument.IsValueSet() ) {
  198. _SetCodePage = TRUE;
  199. _CodePage = (DWORD)CodePageArgument.QueryLong();
  200. } else {
  201. _SetCodePage = FALSE;
  202. }
  203. return TRUE;
  204. }
  205. inline bool IsFarEastCodePage(UINT cp)
  206. {
  207. return cp == 932 || cp == 949 || cp == 936 || cp == 950;
  208. }
  209. inline bool IsFarEastLocale(LANGID langid)
  210. {
  211. // Accepts primay langid only
  212. return langid == LANG_JAPANESE || langid == LANG_KOREAN || langid == LANG_CHINESE;
  213. }
  214. inline bool IsFarEastSystemLocale()
  215. {
  216. return IsFarEastLocale(PRIMARYLANGID(GetSystemDefaultLangID()));
  217. }
  218. BOOLEAN
  219. CHCP::SetCodePage (
  220. )
  221. /*++
  222. Routine Description:
  223. Sets the active code page
  224. Arguments:
  225. None.
  226. Return Value:
  227. TRUE if success, FALSE if syntax error.
  228. Notes:
  229. --*/
  230. {
  231. UINT OldCP = _Screen.QueryCodePage( );
  232. if (IsFarEastSystemLocale() &&
  233. (IsFarEastCodePage(_CodePage) || IsFarEastCodePage(OldCP)) &&
  234. _CodePage != OldCP) {
  235. /*
  236. * This CLS function is needed only if it's FE.
  237. */
  238. _Screen.MoveCursorTo(0, 0);
  239. _Screen.EraseScreenAndResetAttribute();
  240. }
  241. if ( _Screen.SetOutputCodePage( _CodePage ) ) {
  242. if (_Screen.SetCodePage( _CodePage ) ) {
  243. // Comment from NT4J:
  244. // Since FormatMessage checks the current TEB's locale, and the Locale for
  245. // CHCP is initialized when the message class is initialized, the TEB has to
  246. // be updated after the code page is changed successfully. All other code
  247. // pages other than JP and US are ignored.
  248. if (IsFarEastSystemLocale()) {
  249. LANGID LangId;
  250. switch (_CodePage) {
  251. case 932:
  252. LangId = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
  253. break;
  254. case 949:
  255. LangId = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
  256. break;
  257. case 936:
  258. LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
  259. break;
  260. case 950:
  261. LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
  262. break;
  263. default:
  264. LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  265. break;
  266. }
  267. SetThreadLocale(MAKELCID(LangId, SORT_DEFAULT));
  268. }
  269. return DisplayCodePage( );
  270. } else {
  271. // SetOutputCodePage failed.
  272. // Restore the privous input code page
  273. _Screen.SetOutputCodePage( OldCP );
  274. }
  275. }
  276. // Was unable to set the given code page
  277. DisplayMessage( MSG_CHCP_INVALID_CODEPAGE, ERROR_MESSAGE );
  278. return FALSE;
  279. }