ReactOS 0.4.16-dev-1273-g5b94656
doskey.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS DosKey Command
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Provides history and command aliases management for
5 * command-line programs.
6 * COPYRIGHT: Copyright 2008 Christoph von Wittich
7 * Copyright 2013-2017 Hermès Bélusca-Maïto
8 */
9
10#include <stdio.h>
11#include <wchar.h>
12#include <locale.h>
13
14#include <windef.h>
15#include <winbase.h>
16#include <winuser.h>
17#include <wincon.h>
18#include <wincon_undoc.h>
19
20#include "doskey.h"
21
22#define MAX_STRING 2000
24LPWSTR pszExeName = L"cmd.exe";
25
26static VOID SetInsert(DWORD dwFlag)
27{
28 /*
29 * NOTE: Enabling the ENABLE_INSERT_MODE mode can also be done by calling
30 * kernel32:SetConsoleCommandHistoryMode(CONSOLE_OVERSTRIKE) (deprecated).
31 */
32 DWORD dwMode;
34 GetConsoleMode(hConsole, &dwMode);
35 dwMode |= ENABLE_EXTENDED_FLAGS;
36 SetConsoleMode(hConsole, (dwMode & ~ENABLE_INSERT_MODE) | dwFlag);
37}
38
40{
42 PBYTE HistBuf;
43 WCHAR *Hist;
44 WCHAR *HistEnd;
45
46 HistBuf = HeapAlloc(GetProcessHeap(),
48 Length);
49 if (!HistBuf) return;
50 Hist = (WCHAR *)HistBuf;
51 HistEnd = (WCHAR *)&HistBuf[Length];
52
54 {
55 for (; Hist < HistEnd; Hist += wcslen(Hist) + 1)
56 {
57 wprintf(L"%s\n", Hist);
58 }
59 }
60
61 HeapFree(GetProcessHeap(), 0, HistBuf);
62}
63
64static INT SetMacro(LPWSTR definition)
65{
66 WCHAR *name, *nameend, *text, temp;
67
68 name = definition;
69 while (*name == L' ')
70 name++;
71
72 /* error if no '=' found */
73 if ((nameend = wcschr(name, L'=')) != NULL)
74 {
75 text = nameend + 1;
76 while (*text == L' ')
77 text++;
78
79 while (nameend > name && nameend[-1] == L' ')
80 nameend--;
81
82 /* Split rest into name and substitute */
83 temp = *nameend;
84 *nameend = L'\0';
85 /* Don't allow spaces in the name, since such a macro would be unusable */
87 return 0;
88 *nameend = temp;
89 }
90
95 wprintf(szStringBuf, definition);
96 return 1;
97}
98
100{
102 PBYTE AliasBuf;
103 WCHAR *Alias;
104 WCHAR *AliasEnd;
105
106 AliasBuf = HeapAlloc(GetProcessHeap(),
108 Length * sizeof(BYTE));
109 if (!AliasBuf) return;
110 Alias = (WCHAR *)AliasBuf;
111 AliasEnd = (WCHAR *)&AliasBuf[Length];
112
113 if (GetConsoleAliasesW(Alias, Length * sizeof(BYTE), pszExeName))
114 {
115 for (; Alias < AliasEnd; Alias += wcslen(Alias) + 1)
116 {
117 wprintf(L"%s%s\n", Indent, Alias);
118 }
119 }
120
121 HeapFree(GetProcessHeap(), 0, AliasBuf);
122}
123
125{
127 PBYTE ExeNameBuf;
128 WCHAR *ExeName;
129 WCHAR *ExeNameEnd;
130
131 ExeNameBuf = HeapAlloc(GetProcessHeap(),
133 Length * sizeof(BYTE));
134 if (!ExeNameBuf) return;
135 ExeName = (WCHAR *)ExeNameBuf;
136 ExeNameEnd = (WCHAR *)&ExeNameBuf[Length];
137
138 if (GetConsoleAliasExesW(ExeName, Length * sizeof(BYTE)))
139 {
140 for (; ExeName < ExeNameEnd; ExeName += wcslen(ExeName) + 1)
141 {
142 wprintf(L"[%s]\n", ExeName);
143 PrintMacros(ExeName, L" ");
144 wprintf(L"\n");
145 }
146 }
147
148 HeapFree(GetProcessHeap(), 0, ExeNameBuf);
149}
150
151/* Remove starting and ending quotes from a string, if present */
153{
154 WCHAR *end;
155 if (*str == L'"' && *(end = str + wcslen(str) - 1) == L'"')
156 {
157 str++;
158 *end = L'\0';
159 }
160 return str;
161}
162
164{
165 FILE* fp;
168 LPWSTR pszOrgExeName = pszExeName;
169
170 /* Open the file */
171 fp = _wfopen(FileName, L"rt");
172 if (!fp)
173 {
175 return;
176 }
177
178 while (fgetws(line, ARRAYSIZE(line), fp) != NULL)
179 {
180 PWCHAR end;
181
182 if (!*line)
183 continue;
184
185 /* Remove trailing newline character */
186 end = &line[wcslen(line) - 1];
187 if (*end == L'\n')
188 *end = L'\0';
189
190 if (!*line)
191 continue;
192
193 /* Check for any section redefining the current executable name */
194 end = NULL;
195 if (*line == L'[')
196 end = wcschr(line, L']');
197
198 if (end != NULL)
199 {
200 /* New section: change the current executable name */
201
202 *end = L'\0'; // NULL-terminate it
204 if (*pszExeName)
205 {
206 /* Capture the new executable name and truncate it if needed */
210 *end = L'\0'; // Truncate it
213 }
214 else
215 {
216 /* Restore the original current executable name */
217 pszExeName = pszOrgExeName;
218 }
219 }
220 else
221 {
222 /* Set the new macro for the current executable */
223 SetMacro(line);
224 }
225 }
226
227 /* Restore the original current executable name if it has changed */
228 pszExeName = pszOrgExeName;
229
230 /* Close the file and return */
231 fclose(fp);
232 return;
233}
234
235/* Get the start and end of the next command-line argument. */
236static BOOL GetArg(WCHAR **pStart, WCHAR **pEnd)
237{
238 BOOL bInQuotes = FALSE;
239 WCHAR *p = *pEnd;
240 p += wcsspn(p, L" \t");
241 if (!*p)
242 return FALSE;
243 *pStart = p;
244 do
245 {
246 if (!bInQuotes && (*p == L' ' || *p == L'\t'))
247 break;
248 bInQuotes ^= (*p++ == L'"');
249 } while (*p);
250 *pEnd = p;
251 return TRUE;
252}
253
254int
256{
257 LPWSTR pArgStart, pArgEnd;
258
259 setlocale(LC_ALL, "");
260
261 /* Get the full command line using GetCommandLine(). We can't just use argv,
262 * because then a parameter like "gotoroot=cd \" wouldn't be passed completely. */
263 pArgEnd = GetCommandLineW();
264
265 /* Skip the application name */
266 GetArg(&pArgStart, &pArgEnd);
267
268 while (GetArg(&pArgStart, &pArgEnd))
269 {
270 /* NULL-terminate this argument to make processing easier */
271 WCHAR tmp = *pArgEnd;
272 *pArgEnd = L'\0';
273
274 if (!wcscmp(pArgStart, L"/?"))
275 {
277 IDS_HELP,
281 break;
282 }
283 else if (!_wcsnicmp(pArgStart, L"/EXENAME=", 9))
284 {
285 pszExeName = RemoveQuotes(pArgStart + 9);
286 }
287 else if (!_wcsicmp(pArgStart, L"/H") ||
288 !_wcsicmp(pArgStart, L"/HISTORY"))
289 {
290 PrintHistory();
291 }
292 else if (!_wcsnicmp(pArgStart, L"/LISTSIZE=", 10))
293 {
295 }
296 else if (!_wcsicmp(pArgStart, L"/REINSTALL"))
297 {
299 }
300 else if (!_wcsicmp(pArgStart, L"/INSERT"))
301 {
303 }
304 else if (!_wcsicmp(pArgStart, L"/OVERSTRIKE"))
305 {
306 SetInsert(0);
307 }
308 else if (!_wcsicmp(pArgStart, L"/M") ||
309 !_wcsicmp(pArgStart, L"/MACROS"))
310 {
312 }
313 else if (!_wcsnicmp(pArgStart, L"/M:", 3) ||
314 !_wcsnicmp(pArgStart, L"/MACROS:", 8))
315 {
316 LPWSTR exe = RemoveQuotes(wcschr(pArgStart, L':') + 1);
317 if (!_wcsicmp(exe, L"ALL"))
319 else
320 PrintMacros(exe, L"");
321 }
322 else if (!_wcsnicmp(pArgStart, L"/MACROFILE=", 11))
323 {
324 ReadFromFile(RemoveQuotes(pArgStart + 11));
325 }
326 else
327 {
328 /* This is the beginning of a macro definition. It includes
329 * the entire remainder of the line, so first put back the
330 * character that we replaced with NULL. */
331 *pArgEnd = tmp;
332 return SetMacro(pArgStart);
333 }
334
335 if (!tmp) break;
336 pArgEnd++;
337 }
338
339 return 0;
340}
#define IDS_HELP
Definition: resource.h:3
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
wcscpy
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define wcschr
Definition: compat.h:17
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
BOOL WINAPI DECLSPEC_HOTPATCH AddConsoleAliasW(_In_ LPCWSTR Source, _In_ LPCWSTR Target, _In_ LPCWSTR ExeName)
Definition: alias.c:120
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasExesW(LPWSTR lpExeNameBuffer, DWORD ExeNameBufferLength)
Definition: alias.c:543
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasesW(_Out_writes_(AliasBufferLength) LPWSTR AliasBuffer, _In_ DWORD AliasBufferLength, _In_ LPCWSTR ExeName)
Definition: alias.c:380
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasesLengthW(_In_ LPCWSTR ExeName)
Definition: alias.c:472
static WCHAR ExeNameBuffer[EXENAME_LENGTH]
Definition: console.c:43
#define EXENAME_LENGTH
Definition: console.c:40
BOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
Definition: console.c:1571
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode)
Definition: console.c:1608
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleCommandHistoryLengthW(IN LPCWSTR lpExeName)
Definition: history.c:302
VOID WINAPI DECLSPEC_HOTPATCH ExpungeConsoleCommandHistoryW(IN LPCWSTR lpExeName)
Definition: history.c:250
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleCommandHistoryW(OUT LPWSTR lpHistory, IN DWORD cbHistory, IN LPCWSTR lpExeName)
Definition: history.c:274
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleNumberOfCommandsW(IN DWORD dwNumCommands, IN LPCWSTR lpExeName)
Definition: history.c:326
LPWSTR WINAPI GetCommandLineW(void)
Definition: process.c:1338
INT WINAPI DECLSPEC_HOTPATCH LoadStringW(HINSTANCE instance, UINT resource_id, LPWSTR buffer, INT buflen)
Definition: string.c:1220
const WCHAR * text
Definition: package.c:1794
static INT SetMacro(LPWSTR definition)
Definition: doskey.c:64
static VOID PrintHistory(VOID)
Definition: doskey.c:39
static BOOL GetArg(WCHAR **pStart, WCHAR **pEnd)
Definition: doskey.c:236
static VOID PrintMacros(LPWSTR pszExeName, LPWSTR Indent)
Definition: doskey.c:99
static VOID ReadFromFile(LPWSTR FileName)
Definition: doskey.c:163
static VOID SetInsert(DWORD dwFlag)
Definition: doskey.c:26
WCHAR szStringBuf[MAX_STRING]
Definition: doskey.c:23
static LPWSTR RemoveQuotes(LPWSTR str)
Definition: doskey.c:152
#define MAX_STRING
Definition: doskey.c:22
static VOID PrintAllMacros(VOID)
Definition: doskey.c:124
LPWSTR pszExeName
Definition: doskey.c:24
#define IDS_INVALID_MACRO_DEF
Definition: doskey.h:4
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint end
Definition: gl.h:1545
GLfloat GLfloat p
Definition: glext.h:8902
#define LC_ALL
Definition: locale.h:17
_Check_return_ _CRTIMP FILE *__cdecl _wfopen(_In_z_ const wchar_t *_Filename, _In_z_ const wchar_t *_Mode)
_CRTIMP void __cdecl _wperror(_In_opt_z_ const wchar_t *_ErrMsg)
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP int __cdecl _wtoi(_In_z_ const wchar_t *_Str)
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
int wmain()
const WCHAR * str
static calc_node_t temp
Definition: rpn_ieee.c:38
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP size_t __cdecl wcsspn(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
Definition: parser.c:49
Definition: name.c:39
#define setlocale(n, s)
Definition: locale.h:46
int32_t INT
Definition: typedefs.h:58
uint16_t * PWCHAR
Definition: typedefs.h:56
#define wprintf(...)
Definition: whoami.c:18
#define STD_INPUT_HANDLE
Definition: winbase.h:300
#define GetModuleHandle
Definition: winbase.h:3868
#define ENABLE_EXTENDED_FLAGS
Definition: wincon.h:114
#define ENABLE_INSERT_MODE
Definition: wincon.h:112
#define GetConsoleAliasExesLength
Definition: wincon.h:1019
wchar_t * fgetws(wchar_t *buf, int bufsize, FILE *file)
Definition: wmain.c:22
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
unsigned char BYTE
Definition: xxhash.c:193