ReactOS 0.4.15-dev-8231-g29a56f3
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
19/* Console API functions which are absent from wincon.h */
20#define EXENAME_LENGTH (255 + 1)
21
22VOID
25
29 DWORD cbHistory,
31
35
36BOOL
40
41#include "doskey.h"
42
43#define MAX_STRING 2000
45LPWSTR pszExeName = L"cmd.exe";
46
47static VOID SetInsert(DWORD dwFlag)
48{
49 /*
50 * NOTE: Enabling the ENABLE_INSERT_MODE mode can also be done by calling
51 * kernel32:SetConsoleCommandHistoryMode(CONSOLE_OVERSTRIKE) (deprecated).
52 */
53 DWORD dwMode;
55 GetConsoleMode(hConsole, &dwMode);
56 dwMode |= ENABLE_EXTENDED_FLAGS;
57 SetConsoleMode(hConsole, (dwMode & ~ENABLE_INSERT_MODE) | dwFlag);
58}
59
61{
63 PBYTE HistBuf;
64 WCHAR *Hist;
65 WCHAR *HistEnd;
66
67 HistBuf = HeapAlloc(GetProcessHeap(),
69 Length);
70 if (!HistBuf) return;
71 Hist = (WCHAR *)HistBuf;
72 HistEnd = (WCHAR *)&HistBuf[Length];
73
75 {
76 for (; Hist < HistEnd; Hist += wcslen(Hist) + 1)
77 {
78 wprintf(L"%s\n", Hist);
79 }
80 }
81
82 HeapFree(GetProcessHeap(), 0, HistBuf);
83}
84
85static INT SetMacro(LPWSTR definition)
86{
87 WCHAR *name, *nameend, *text, temp;
88
89 name = definition;
90 while (*name == L' ')
91 name++;
92
93 /* error if no '=' found */
94 if ((nameend = wcschr(name, L'=')) != NULL)
95 {
96 text = nameend + 1;
97 while (*text == L' ')
98 text++;
99
100 while (nameend > name && nameend[-1] == L' ')
101 nameend--;
102
103 /* Split rest into name and substitute */
104 temp = *nameend;
105 *nameend = L'\0';
106 /* Don't allow spaces in the name, since such a macro would be unusable */
108 return 0;
109 *nameend = temp;
110 }
111
116 wprintf(szStringBuf, definition);
117 return 1;
118}
119
121{
123 PBYTE AliasBuf;
124 WCHAR *Alias;
125 WCHAR *AliasEnd;
126
127 AliasBuf = HeapAlloc(GetProcessHeap(),
129 Length * sizeof(BYTE));
130 if (!AliasBuf) return;
131 Alias = (WCHAR *)AliasBuf;
132 AliasEnd = (WCHAR *)&AliasBuf[Length];
133
134 if (GetConsoleAliasesW(Alias, Length * sizeof(BYTE), pszExeName))
135 {
136 for (; Alias < AliasEnd; Alias += wcslen(Alias) + 1)
137 {
138 wprintf(L"%s%s\n", Indent, Alias);
139 }
140 }
141
142 HeapFree(GetProcessHeap(), 0, AliasBuf);
143}
144
146{
148 PBYTE ExeNameBuf;
149 WCHAR *ExeName;
150 WCHAR *ExeNameEnd;
151
152 ExeNameBuf = HeapAlloc(GetProcessHeap(),
154 Length * sizeof(BYTE));
155 if (!ExeNameBuf) return;
156 ExeName = (WCHAR *)ExeNameBuf;
157 ExeNameEnd = (WCHAR *)&ExeNameBuf[Length];
158
159 if (GetConsoleAliasExesW(ExeName, Length * sizeof(BYTE)))
160 {
161 for (; ExeName < ExeNameEnd; ExeName += wcslen(ExeName) + 1)
162 {
163 wprintf(L"[%s]\n", ExeName);
164 PrintMacros(ExeName, L" ");
165 wprintf(L"\n");
166 }
167 }
168
169 HeapFree(GetProcessHeap(), 0, ExeNameBuf);
170}
171
172/* Remove starting and ending quotes from a string, if present */
174{
175 WCHAR *end;
176 if (*str == L'"' && *(end = str + wcslen(str) - 1) == L'"')
177 {
178 str++;
179 *end = L'\0';
180 }
181 return str;
182}
183
185{
186 FILE* fp;
189 LPWSTR pszOrgExeName = pszExeName;
190
191 /* Open the file */
192 fp = _wfopen(FileName, L"rt");
193 if (!fp)
194 {
196 return;
197 }
198
199 while (fgetws(line, ARRAYSIZE(line), fp) != NULL)
200 {
201 PWCHAR end;
202
203 if (!*line)
204 continue;
205
206 /* Remove trailing newline character */
207 end = &line[wcslen(line) - 1];
208 if (*end == L'\n')
209 *end = L'\0';
210
211 if (!*line)
212 continue;
213
214 /* Check for any section redefining the current executable name */
215 end = NULL;
216 if (*line == L'[')
217 end = wcschr(line, L']');
218
219 if (end != NULL)
220 {
221 /* New section: change the current executable name */
222
223 *end = L'\0'; // NULL-terminate it
225 if (*pszExeName)
226 {
227 /* Capture the new executable name and truncate it if needed */
231 *end = L'\0'; // Truncate it
234 }
235 else
236 {
237 /* Restore the original current executable name */
238 pszExeName = pszOrgExeName;
239 }
240 }
241 else
242 {
243 /* Set the new macro for the current executable */
244 SetMacro(line);
245 }
246 }
247
248 /* Restore the original current executable name if it has changed */
249 pszExeName = pszOrgExeName;
250
251 /* Close the file and return */
252 fclose(fp);
253 return;
254}
255
256/* Get the start and end of the next command-line argument. */
257static BOOL GetArg(WCHAR **pStart, WCHAR **pEnd)
258{
259 BOOL bInQuotes = FALSE;
260 WCHAR *p = *pEnd;
261 p += wcsspn(p, L" \t");
262 if (!*p)
263 return FALSE;
264 *pStart = p;
265 do
266 {
267 if (!bInQuotes && (*p == L' ' || *p == L'\t'))
268 break;
269 bInQuotes ^= (*p++ == L'"');
270 } while (*p);
271 *pEnd = p;
272 return TRUE;
273}
274
275int
277{
278 LPWSTR pArgStart, pArgEnd;
279
280 setlocale(LC_ALL, "");
281
282 /* Get the full command line using GetCommandLine(). We can't just use argv,
283 * because then a parameter like "gotoroot=cd \" wouldn't be passed completely. */
284 pArgEnd = GetCommandLineW();
285
286 /* Skip the application name */
287 GetArg(&pArgStart, &pArgEnd);
288
289 while (GetArg(&pArgStart, &pArgEnd))
290 {
291 /* NULL-terminate this argument to make processing easier */
292 WCHAR tmp = *pArgEnd;
293 *pArgEnd = L'\0';
294
295 if (!wcscmp(pArgStart, L"/?"))
296 {
298 IDS_HELP,
302 break;
303 }
304 else if (!_wcsnicmp(pArgStart, L"/EXENAME=", 9))
305 {
306 pszExeName = RemoveQuotes(pArgStart + 9);
307 }
308 else if (!wcsicmp(pArgStart, L"/H") ||
309 !wcsicmp(pArgStart, L"/HISTORY"))
310 {
311 PrintHistory();
312 }
313 else if (!_wcsnicmp(pArgStart, L"/LISTSIZE=", 10))
314 {
316 }
317 else if (!wcsicmp(pArgStart, L"/REINSTALL"))
318 {
320 }
321 else if (!wcsicmp(pArgStart, L"/INSERT"))
322 {
324 }
325 else if (!wcsicmp(pArgStart, L"/OVERSTRIKE"))
326 {
327 SetInsert(0);
328 }
329 else if (!wcsicmp(pArgStart, L"/M") ||
330 !wcsicmp(pArgStart, L"/MACROS"))
331 {
333 }
334 else if (!_wcsnicmp(pArgStart, L"/M:", 3) ||
335 !_wcsnicmp(pArgStart, L"/MACROS:", 8))
336 {
337 LPWSTR exe = RemoveQuotes(wcschr(pArgStart, L':') + 1);
338 if (!wcsicmp(exe, L"ALL"))
340 else
341 PrintMacros(exe, L"");
342 }
343 else if (!_wcsnicmp(pArgStart, L"/MACROFILE=", 11))
344 {
345 ReadFromFile(RemoveQuotes(pArgStart + 11));
346 }
347 else
348 {
349 /* This is the beginning of a macro definition. It includes
350 * the entire remainder of the line, so first put back the
351 * character that we replaced with NULL. */
352 *pArgEnd = tmp;
353 return SetMacro(pArgStart);
354 }
355
356 if (!tmp) break;
357 pArgEnd++;
358 }
359
360 return 0;
361}
#define IDS_HELP
Definition: resource.h:3
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
#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
#define wcsicmp
Definition: compat.h:15
BOOL WINAPI DECLSPEC_HOTPATCH AddConsoleAliasW(LPCWSTR lpSource, LPCWSTR lpTarget, LPCWSTR lpExeName)
Definition: alias.c:120
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasesW(LPWSTR AliasBuffer, DWORD AliasBufferLength, LPWSTR ExeName)
Definition: alias.c:376
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasesLengthW(LPWSTR lpExeName)
Definition: alias.c:466
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasExesW(LPWSTR lpExeNameBuffer, DWORD ExeNameBufferLength)
Definition: alias.c:535
static WCHAR ExeNameBuffer[EXENAME_LENGTH]
Definition: console.c:43
BOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
Definition: console.c:1569
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode)
Definition: console.c:1606
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2013
const WCHAR * text
Definition: package.c:1799
DWORD WINAPI GetConsoleCommandHistoryLengthW(LPCWSTR lpExeName)
static INT SetMacro(LPWSTR definition)
Definition: doskey.c:85
VOID WINAPI ExpungeConsoleCommandHistoryW(LPCWSTR lpExeName)
static VOID PrintHistory(VOID)
Definition: doskey.c:60
#define EXENAME_LENGTH
Definition: doskey.c:20
BOOL WINAPI SetConsoleNumberOfCommandsW(DWORD dwNumCommands, LPCWSTR lpExeName)
static BOOL GetArg(WCHAR **pStart, WCHAR **pEnd)
Definition: doskey.c:257
static VOID PrintMacros(LPWSTR pszExeName, LPWSTR Indent)
Definition: doskey.c:120
static VOID ReadFromFile(LPWSTR FileName)
Definition: doskey.c:184
static VOID SetInsert(DWORD dwFlag)
Definition: doskey.c:47
WCHAR szStringBuf[MAX_STRING]
Definition: doskey.c:44
static LPWSTR RemoveQuotes(LPWSTR str)
Definition: doskey.c:173
#define MAX_STRING
Definition: doskey.c:43
static VOID PrintAllMacros(VOID)
Definition: doskey.c:145
LPWSTR pszExeName
Definition: doskey.c:45
DWORD WINAPI GetConsoleCommandHistoryW(LPWSTR lpHistory, DWORD cbHistory, LPCWSTR lpExeName)
#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)
static DWORD LPSTR lpExeName
Definition: process.c:72
_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
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
_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:267
#define GetModuleHandle
Definition: winbase.h:3827
#define ENABLE_EXTENDED_FLAGS
Definition: wincon.h:85
#define ENABLE_INSERT_MODE
Definition: wincon.h:83
#define GetConsoleAliasExesLength
Definition: wincon.h:774
#define WINAPI
Definition: msvc.h:6
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
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
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
unsigned char BYTE
Definition: xxhash.c:193