[INTL]
[reactos.git] / reactos / base / applications / cmdutils / help / help.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS help utility
4 * FILE: base/applications/cmdutils/help/help.c
5 * PURPOSE: Provide help for command-line utilities
6 * PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <wchar.h>
13
14 #define WIN32_NO_STATUS
15 #include <windef.h>
16 #include <winbase.h>
17 #include <winuser.h>
18 #include <wincon.h>
19
20 #include "help.h"
21 #include "resource.h"
22
23 BOOL IsConsoleHandle(HANDLE hHandle)
24 {
25 DWORD dwMode;
26
27 /* Check whether the handle may be that of a console... */
28 if ((GetFileType(hHandle) & FILE_TYPE_CHAR) == 0) return FALSE;
29
30 /*
31 * It may be. Perform another test... The idea comes from the
32 * MSDN description of the WriteConsole API:
33 *
34 * "WriteConsole fails if it is used with a standard handle
35 * that is redirected to a file. If an application processes
36 * multilingual output that can be redirected, determine whether
37 * the output handle is a console handle (one method is to call
38 * the GetConsoleMode function and check whether it succeeds).
39 * If the handle is a console handle, call WriteConsole. If the
40 * handle is not a console handle, the output is redirected and
41 * you should call WriteFile to perform the I/O."
42 */
43 return GetConsoleMode(hHandle, &dwMode);
44 }
45
46 VOID PrintResourceString(INT resID, ...)
47 {
48 HANDLE OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
49 WCHAR tmpBuffer[RC_STRING_MAX_SIZE];
50 va_list arg_ptr;
51
52 va_start(arg_ptr, resID);
53 LoadStringW(GetModuleHandleW(NULL), resID, tmpBuffer, RC_STRING_MAX_SIZE);
54
55 // FIXME: Optimize by using Win32 console functions.
56 if (IsConsoleHandle(OutputHandle))
57 {
58 _vcwprintf(tmpBuffer, arg_ptr);
59 }
60 else
61 {
62 vwprintf(tmpBuffer, arg_ptr);
63 }
64
65 va_end(arg_ptr);
66 }
67
68 BOOL IsInternalCommand(LPCWSTR Cmd)
69 {
70 size_t i;
71 int res;
72
73 /* Invalid command */
74 if (!Cmd) return FALSE;
75
76 for (i = 0; i < sizeof(InternalCommands)/sizeof(InternalCommands[0]); ++i)
77 {
78 res = _wcsicmp(InternalCommands[i], Cmd);
79 if (res == 0)
80 {
81 /* This is an internal command */
82 return TRUE;
83 }
84 else if (res > 0)
85 {
86 /*
87 * The internal commands list is sorted in alphabetical order.
88 * We can quit the loop immediately since the current internal
89 * command is lexically greater than the command to be tested.
90 */
91 break;
92 }
93 }
94
95 /* Command not found */
96 return FALSE;
97 }
98
99 int wmain(int argc, WCHAR* argv[])
100 {
101 WCHAR CmdLine[CMDLINE_LENGTH];
102
103 /*
104 * If the user hasn't asked for specific help,
105 * then print out the list of available commands.
106 */
107 if (argc <= 1)
108 {
109 PrintResourceString(IDS_HELP1);
110 PrintResourceString(IDS_HELP2);
111 return 0;
112 }
113
114 /*
115 * Bad usage (too much options) or we use the /? switch.
116 * Display help for the help command.
117 */
118 if ((argc > 2) || (wcscmp(argv[1], L"/?") == 0))
119 {
120 PrintResourceString(IDS_USAGE);
121 return 0;
122 }
123
124 /*
125 * If the command is not an internal one,
126 * display an information message and exit.
127 */
128 if (!IsInternalCommand(argv[1]))
129 {
130 PrintResourceString(IDS_NO_ENTRY, argv[1]);
131 return 0;
132 }
133
134 /*
135 * Run "<command> /?" in the current command processor.
136 */
137 wcsncpy(CmdLine, argv[1], CMDLINE_LENGTH - wcslen(CmdLine));
138 wcsncat(CmdLine, L" /?" , CMDLINE_LENGTH - wcslen(CmdLine));
139
140 _flushall();
141 return _wsystem(CmdLine);
142 }
143
144 /* EOF */