Hopefully create a branch and not destroy the svn repository.
[reactos.git] / base / applications / cmdutils / doskey / doskey.c
1 #include <windows.h>
2 #include <stdio.h>
3 #include <tchar.h>
4 #include "doskey.h"
5
6 #define MAX_STRING 2000
7 TCHAR szStringBuf[MAX_STRING];
8 LPTSTR pszExeName = _T("cmd.exe");
9
10 static VOID SetInsert(DWORD dwFlag)
11 {
12 DWORD dwMode;
13 HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
14 GetConsoleMode(hConsole, &dwMode);
15 dwMode |= ENABLE_EXTENDED_FLAGS;
16 SetConsoleMode(hConsole, (dwMode & ~ENABLE_INSERT_MODE) | dwFlag);
17 }
18
19 static VOID PrintHistory(VOID)
20 {
21 DWORD Length = GetConsoleCommandHistoryLength(pszExeName);
22 DWORD BufferLength;
23 PBYTE HistBuf;
24 TCHAR *Hist;
25 TCHAR *HistEnd;
26
27 /* On Windows, the ANSI version of GetConsoleCommandHistory requires
28 * a buffer twice as large as the actual history length. */
29 BufferLength = Length * (sizeof(WCHAR) / sizeof(TCHAR)) * sizeof(BYTE);
30
31 HistBuf = HeapAlloc(GetProcessHeap(),
32 HEAP_ZERO_MEMORY,
33 BufferLength);
34 if (!HistBuf) return;
35 Hist = (TCHAR *)HistBuf;
36 HistEnd = (TCHAR *)&HistBuf[Length];
37
38 if (GetConsoleCommandHistory(Hist, BufferLength, pszExeName))
39 for (; Hist < HistEnd; Hist += _tcslen(Hist) + 1)
40 _tprintf(_T("%s\n"), Hist);
41
42 HeapFree(GetProcessHeap(), 0, HistBuf);
43 }
44
45 static INT SetMacro(LPTSTR definition)
46 {
47 TCHAR *name, *nameend, *text, temp;
48
49 name = definition;
50 while (*name == _T(' '))
51 name++;
52
53 /* error if no '=' found */
54 if ((nameend = _tcschr(name, _T('='))) != NULL)
55 {
56 text = nameend + 1;
57 while (*text == _T(' '))
58 text++;
59
60 while (nameend > name && nameend[-1] == _T(' '))
61 nameend--;
62
63 /* Split rest into name and substitute */
64 temp = *nameend;
65 *nameend = _T('\0');
66 /* Don't allow spaces in the name, since such a macro would be unusable */
67 if (!_tcschr(name, _T(' ')) && AddConsoleAlias(name, text, pszExeName))
68 return 0;
69 *nameend = temp;
70 }
71
72 LoadString(GetModuleHandle(NULL), IDS_INVALID_MACRO_DEF, szStringBuf, MAX_STRING);
73 _tprintf(szStringBuf, definition);
74 return 1;
75 }
76
77 static VOID PrintMacros(LPTSTR pszExeName, LPTSTR Indent)
78 {
79 DWORD Length = GetConsoleAliasesLength(pszExeName);
80 PBYTE AliasBuf;
81 TCHAR *Alias;
82 TCHAR *AliasEnd;
83
84 AliasBuf = HeapAlloc(GetProcessHeap(),
85 HEAP_ZERO_MEMORY,
86 Length * sizeof(BYTE));
87 if (!AliasBuf) return;
88 Alias = (TCHAR *)AliasBuf;
89 AliasEnd = (TCHAR *)&AliasBuf[Length];
90
91 if (GetConsoleAliases(Alias, Length * sizeof(BYTE), pszExeName))
92 for (; Alias < AliasEnd; Alias += _tcslen(Alias) + 1)
93 _tprintf(_T("%s%s\n"), Indent, Alias);
94
95 HeapFree(GetProcessHeap(), 0, AliasBuf);
96 }
97
98 static VOID PrintAllMacros(VOID)
99 {
100 DWORD Length = GetConsoleAliasExesLength();
101 PBYTE ExeNameBuf;
102 TCHAR *ExeName;
103 TCHAR *ExeNameEnd;
104
105 ExeNameBuf = HeapAlloc(GetProcessHeap(),
106 HEAP_ZERO_MEMORY,
107 Length * sizeof(BYTE));
108 if (!ExeNameBuf) return;
109 ExeName = (TCHAR *)ExeNameBuf;
110 ExeNameEnd = (TCHAR *)&ExeNameBuf[Length];
111
112 if (GetConsoleAliasExes(ExeName, Length * sizeof(BYTE)))
113 {
114 for (; ExeName < ExeNameEnd; ExeName += _tcslen(ExeName) + 1)
115 {
116 _tprintf(_T("[%s]\n"), ExeName);
117 PrintMacros(ExeName, _T(" "));
118 _tprintf(_T("\n"));
119 }
120 }
121
122 HeapFree(GetProcessHeap(), 0, ExeNameBuf);
123 }
124
125 static VOID ReadFromFile(LPTSTR param)
126 {
127 FILE* fp;
128 TCHAR line[MAX_PATH];
129
130 fp = _tfopen(param, _T("r"));
131 if (!fp)
132 {
133 #ifdef UNICODE
134 _wperror(param);
135 #else
136 perror(param);
137 #endif
138 return;
139 }
140
141 while ( _fgetts(line, MAX_PATH, fp) != NULL)
142 {
143 /* Remove newline character */
144 TCHAR *end = &line[_tcslen(line) - 1];
145 if (*end == _T('\n'))
146 *end = _T('\0');
147
148 if (*line)
149 SetMacro(line);
150 }
151
152 fclose(fp);
153 return;
154 }
155
156 /* Get the start and end of the next command-line argument. */
157 static BOOL GetArg(TCHAR **pStart, TCHAR **pEnd)
158 {
159 BOOL bInQuotes = FALSE;
160 TCHAR *p = *pEnd;
161 p += _tcsspn(p, _T(" \t"));
162 if (!*p)
163 return FALSE;
164 *pStart = p;
165 do
166 {
167 if (!bInQuotes && (*p == _T(' ') || *p == _T('\t')))
168 break;
169 bInQuotes ^= (*p++ == _T('"'));
170 } while (*p);
171 *pEnd = p;
172 return TRUE;
173 }
174
175 /* Remove starting and ending quotes from a string, if present */
176 static LPTSTR RemoveQuotes(LPTSTR str)
177 {
178 TCHAR *end;
179 if (*str == _T('"') && *(end = str + _tcslen(str) - 1) == _T('"'))
180 {
181 str++;
182 *end = _T('\0');
183 }
184 return str;
185 }
186
187 int
188 _tmain(VOID)
189 {
190 /* Get the full command line using GetCommandLine(). We can't just use argv,
191 * because then a parameter like "gotoroot=cd \" wouldn't be passed completely. */
192 TCHAR *pArgStart;
193 TCHAR *pArgEnd = GetCommandLine();
194
195 /* Skip the application name */
196 GetArg(&pArgStart, &pArgEnd);
197
198 while (GetArg(&pArgStart, &pArgEnd))
199 {
200 /* NUL-terminate this argument to make processing easier */
201 TCHAR tmp = *pArgEnd;
202 *pArgEnd = _T('\0');
203
204 if (!_tcscmp(pArgStart, _T("/?")))
205 {
206 LoadString(GetModuleHandle(NULL), IDS_HELP, szStringBuf, MAX_STRING);
207 _tprintf(szStringBuf);
208 break;
209 }
210 else if (!_tcsnicmp(pArgStart, _T("/EXENAME="), 9))
211 {
212 pszExeName = RemoveQuotes(pArgStart + 9);
213 }
214 else if (!_tcsicmp(pArgStart, _T("/H")) ||
215 !_tcsicmp(pArgStart, _T("/HISTORY")))
216 {
217 PrintHistory();
218 }
219 else if (!_tcsnicmp(pArgStart, _T("/LISTSIZE="), 10))
220 {
221 SetConsoleNumberOfCommands(_ttoi(pArgStart + 10), pszExeName);
222 }
223 else if (!_tcsicmp(pArgStart, _T("/REINSTALL")))
224 {
225 ExpungeConsoleCommandHistory(pszExeName);
226 }
227 else if (!_tcsicmp(pArgStart, _T("/INSERT")))
228 {
229 SetInsert(ENABLE_INSERT_MODE);
230 }
231 else if (!_tcsicmp(pArgStart, _T("/OVERSTRIKE")))
232 {
233 SetInsert(0);
234 }
235 else if (!_tcsicmp(pArgStart, _T("/M")) ||
236 !_tcsicmp(pArgStart, _T("/MACROS")))
237 {
238 PrintMacros(pszExeName, _T(""));
239 }
240 else if (!_tcsnicmp(pArgStart, _T("/M:"), 3) ||
241 !_tcsnicmp(pArgStart, _T("/MACROS:"), 8))
242 {
243 LPTSTR exe = RemoveQuotes(_tcschr(pArgStart, _T(':')) + 1);
244 if (!_tcsicmp(exe, _T("ALL")))
245 PrintAllMacros();
246 else
247 PrintMacros(exe, _T(""));
248 }
249 else if (!_tcsnicmp(pArgStart, _T("/MACROFILE="), 11))
250 {
251 ReadFromFile(RemoveQuotes(pArgStart + 11));
252 }
253 else
254 {
255 /* This is the beginning of a macro definition. It includes
256 * the entire remainder of the line, so first put back the
257 * character that we replaced with NUL. */
258 *pArgEnd = tmp;
259 return SetMacro(pArgStart);
260 }
261
262 if (!tmp) break;
263 pArgEnd++;
264 }
265
266 return 0;
267 }