ReactOS  0.4.12-dev-18-gf469aca
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 
22 VOID
23 WINAPI
25 
26 DWORD
27 WINAPI
29  DWORD cbHistory,
31 
32 DWORD
33 WINAPI
35 
36 BOOL
37 WINAPI
40 
41 #include "doskey.h"
42 
43 #define MAX_STRING 2000
45 LPWSTR pszExeName = L"cmd.exe";
46 
47 static 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 
74  if (GetConsoleCommandHistoryW(Hist, Length, pszExeName))
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 
85 static 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 */
107  if (!wcschr(name, L' ') && AddConsoleAliasW(name, text, pszExeName))
108  return 0;
109  *nameend = temp;
110  }
111 
114  szStringBuf,
116  wprintf(szStringBuf, definition);
117  return 1;
118 }
119 
121 {
122  DWORD Length = GetConsoleAliasesLengthW(pszExeName);
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  {
195  _wperror(FileName);
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
224  pszExeName = RemoveQuotes(line + 1);
225  if (*pszExeName)
226  {
227  /* Capture the new executable name and truncate it if needed */
228  end = &pszExeName[wcslen(pszExeName)];
229  if (end - pszExeName >= EXENAME_LENGTH)
230  end = &pszExeName[EXENAME_LENGTH - 1];
231  *end = L'\0'; // Truncate it
232  wcscpy(ExeNameBuffer, pszExeName);
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. */
257 static 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 
275 int
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,
299  szStringBuf,
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  {
315  SetConsoleNumberOfCommandsW(_wtoi(pArgStart + 10), pszExeName);
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"))
339  PrintAllMacros();
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 TRUE
Definition: types.h:120
WCHAR szStringBuf[MAX_STRING]
Definition: doskey.c:44
static WCHAR ExeNameBuffer[EXENAME_LENGTH]
Definition: console.c:43
_Check_return_ _CRTIMP FILE *__cdecl _wfopen(_In_z_ const wchar_t *_Filename, _In_z_ const wchar_t *_Mode)
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * text
Definition: package.c:1827
_Check_return_ _CRTIMP int __cdecl _wtoi(_In_z_ const wchar_t *_Str)
BOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
Definition: console.c:1571
_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)
static INT SetMacro(LPWSTR definition)
Definition: doskey.c:85
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:152
GLuint GLuint end
Definition: gl.h:1545
uint16_t * PWCHAR
Definition: typedefs.h:54
#define IDS_INVALID_MACRO_DEF
Definition: doskey.h:4
static VOID PrintMacros(LPWSTR pszExeName, LPWSTR Indent)
Definition: doskey.c:120
#define wprintf(...)
Definition: whoami.c:18
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
int32_t INT
Definition: typedefs.h:56
LPWSTR pszExeName
Definition: doskey.c:45
static DWORD LPSTR lpExeName
Definition: process.c:72
VOID WINAPI ExpungeConsoleCommandHistoryW(LPCWSTR lpExeName)
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode)
Definition: console.c:1608
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2043
int wmain(VOID)
Definition: doskey.c:276
const WCHAR * str
smooth NULL
Definition: ftsmooth.c:416
Definition: parser.c:48
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasesW(LPWSTR AliasBuffer, DWORD AliasBufferLength, LPWSTR ExeName)
Definition: alias.c:376
#define STD_INPUT_HANDLE
Definition: winbase.h:264
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasExesW(LPWSTR lpExeNameBuffer, DWORD ExeNameBufferLength)
Definition: alias.c:535
#define LC_ALL
Definition: locale.h:25
unsigned int BOOL
Definition: ntddk_ex.h:94
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
#define GetConsoleAliasExesLength
Definition: wincon.h:762
static VOID PrintHistory(VOID)
Definition: doskey.c:60
#define MAX_PATH
Definition: compat.h:26
BOOL WINAPI DECLSPEC_HOTPATCH AddConsoleAliasW(LPCWSTR lpSource, LPCWSTR lpTarget, LPCWSTR lpExeName)
Definition: alias.c:120
unsigned long DWORD
Definition: ntddk_ex.h:95
static BOOL GetArg(WCHAR **pStart, WCHAR **pEnd)
Definition: doskey.c:257
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static VOID SetInsert(DWORD dwFlag)
Definition: doskey.c:47
static const WCHAR L[]
Definition: oid.c:1087
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_CRTIMP void __cdecl _wperror(_In_opt_z_ const wchar_t *_ErrMsg)
static stack_node_t temp
Definition: rpn.c:18
DWORD WINAPI GetConsoleCommandHistoryLengthW(LPCWSTR lpExeName)
DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleAliasesLengthW(LPWSTR lpExeName)
Definition: alias.c:466
#define WINAPI
Definition: msvc.h:20
#define wcsicmp
Definition: string.h:1152
unsigned char BYTE
Definition: ntddk_ex.h:96
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define GetModuleHandle
Definition: winbase.h:3641
#define ENABLE_INSERT_MODE
Definition: wincon.h:80
BOOL WINAPI SetConsoleNumberOfCommandsW(DWORD dwNumCommands, LPCWSTR lpExeName)
#define IDS_HELP
Definition: resource.h:3
#define ENABLE_EXTENDED_FLAGS
Definition: wincon.h:82
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
DWORD WINAPI GetConsoleCommandHistoryW(LPWSTR lpHistory, DWORD cbHistory, LPCWSTR lpExeName)
wchar_t * fgetws(wchar_t *buf, int bufsize, FILE *file)
Definition: wmain.c:22
#define setlocale(n, s)
Definition: locale.h:46
#define EXENAME_LENGTH
Definition: doskey.c:20
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static LPWSTR RemoveQuotes(LPWSTR str)
Definition: doskey.c:173
DWORD HDC HDC DVTARGETDEVICE DWORD dwMode
Definition: msvc.h:106
BYTE * PBYTE
Definition: pedump.c:66
_Check_return_ _CRTIMP size_t __cdecl wcsspn(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
#define MAX_STRING
Definition: doskey.c:43
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:394
static VOID ReadFromFile(LPWSTR FileName)
Definition: doskey.c:184
static VOID PrintAllMacros(VOID)
Definition: doskey.c:145
GLuint const GLchar * name
Definition: glext.h:6031