Sync with trunk r63502.
[reactos.git] / 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_REMOTE) != FILE_TYPE_CHAR)
29 return FALSE;
30
31 /*
32 * It may be. Perform another test... The idea comes from the
33 * MSDN description of the WriteConsole API:
34 *
35 * "WriteConsole fails if it is used with a standard handle
36 * that is redirected to a file. If an application processes
37 * multilingual output that can be redirected, determine whether
38 * the output handle is a console handle (one method is to call
39 * the GetConsoleMode function and check whether it succeeds).
40 * If the handle is a console handle, call WriteConsole. If the
41 * handle is not a console handle, the output is redirected and
42 * you should call WriteFile to perform the I/O."
43 */
44 return GetConsoleMode(hHandle, &dwMode);
45 }
46
47 VOID PrintResourceString(INT resID, ...)
48 {
49 HANDLE OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
50 WCHAR tmpBuffer[RC_STRING_MAX_SIZE];
51 va_list arg_ptr;
52
53 va_start(arg_ptr, resID);
54 LoadStringW(GetModuleHandleW(NULL), resID, tmpBuffer, RC_STRING_MAX_SIZE);
55
56 // FIXME: Optimize by using Win32 console functions.
57 if (IsConsoleHandle(OutputHandle))
58 {
59 vfwprintf(stdout, tmpBuffer, arg_ptr);
60 }
61 else
62 {
63 vwprintf(tmpBuffer, arg_ptr);
64 }
65
66 va_end(arg_ptr);
67 }
68
69 BOOL IsInternalCommand(LPCWSTR Cmd)
70 {
71 size_t i;
72 int res;
73
74 /* Invalid command */
75 if (!Cmd) return FALSE;
76
77 for (i = 0; i < sizeof(InternalCommands)/sizeof(InternalCommands[0]); ++i)
78 {
79 res = _wcsicmp(InternalCommands[i], Cmd);
80 if (res == 0)
81 {
82 /* This is an internal command */
83 return TRUE;
84 }
85 else if (res > 0)
86 {
87 /*
88 * The internal commands list is sorted in alphabetical order.
89 * We can quit the loop immediately since the current internal
90 * command is lexically greater than the command to be tested.
91 */
92 break;
93 }
94 }
95
96 /* Command not found */
97 return FALSE;
98 }
99
100 int wmain(int argc, WCHAR* argv[])
101 {
102 WCHAR CmdLine[CMDLINE_LENGTH];
103
104 /*
105 * If the user hasn't asked for specific help,
106 * then print out the list of available commands.
107 */
108 if (argc <= 1)
109 {
110 PrintResourceString(IDS_HELP1);
111 PrintResourceString(IDS_HELP2);
112 return 0;
113 }
114
115 /*
116 * Bad usage (too much options) or we use the /? switch.
117 * Display help for the help command.
118 */
119 if ((argc > 2) || (wcscmp(argv[1], L"/?") == 0))
120 {
121 PrintResourceString(IDS_USAGE);
122 return 0;
123 }
124
125 /*
126 * If the command is not an internal one,
127 * display an information message and exit.
128 */
129 if (!IsInternalCommand(argv[1]))
130 {
131 PrintResourceString(IDS_NO_ENTRY, argv[1]);
132 return 0;
133 }
134
135 /*
136 * Run "<command> /?" in the current command processor.
137 */
138 wcsncpy(CmdLine, argv[1], CMDLINE_LENGTH - wcslen(CmdLine));
139 wcsncat(CmdLine, L" /?" , CMDLINE_LENGTH - wcslen(CmdLine));
140
141 _flushall();
142 return _wsystem(CmdLine);
143 }
144
145 /* EOF */