blob: 7a4f9a1d3cbe849ed7f65f0b01abd4fe326a5ab8 [file] [log] [blame]
Dave Pickles74f440e1999-06-06 15:24:04 +00001/*
Dan Kegel39857442006-09-03 21:13:08 -07002 * CMD - Wine-compatible command line interface - built-in functions.
Dave Pickles74f440e1999-06-06 15:24:04 +00003 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00004 * Copyright (C) 1999 D A Pickles
Jason Edmeades1ee75382007-09-11 21:43:08 +01005 * Copyright (C) 2007 J Edmeades
Dave Pickles74f440e1999-06-06 15:24:04 +00006 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00007 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000020 */
21
22/*
23 * NOTES:
Dave Pickles74f440e1999-06-06 15:24:04 +000024 * On entry to each function, global variables quals, param1, param2 contain
25 * the qualifiers (uppercased and concatenated) and parameters entered, with
26 * environment-variable and batch parameter substitution already done.
27 */
28
29/*
30 * FIXME:
Dave Pickles036a9f71999-07-10 11:36:45 +000031 * - No support for pipes, shell parameters
Dave Pickles74f440e1999-06-06 15:24:04 +000032 * - Lots of functionality missing from builtins
33 * - Messages etc need international support
34 */
35
Mike McCormack7d665672006-01-16 20:41:34 +010036#define WIN32_LEAN_AND_MEAN
37
Dave Pickles74f440e1999-06-06 15:24:04 +000038#include "wcmd.h"
Jason Edmeades69194ce2007-02-26 23:04:40 +000039#include <shellapi.h>
Jason Edmeades0efa91d2007-03-04 22:33:27 +000040#include "wine/debug.h"
41
42WINE_DEFAULT_DEBUG_CHANNEL(cmd);
Dave Pickles74f440e1999-06-06 15:24:04 +000043
Jason Edmeades54d890c2007-06-15 20:59:28 +010044static void WCMD_part_execute(CMD_LIST **commands, WCHAR *firstcmd, WCHAR *variable,
45 WCHAR *value, BOOL isIF, BOOL conditionTRUE);
Dave Pickles036a9f71999-07-10 11:36:45 +000046
Mike McCormack9643b792004-03-22 22:56:58 +000047struct env_stack *saved_environment;
Jason Edmeades365f86f2007-02-23 22:17:28 +000048struct env_stack *pushd_directories;
Mike McCormack9643b792004-03-22 22:56:58 +000049
Dave Pickles74f440e1999-06-06 15:24:04 +000050extern HINSTANCE hinst;
Jason Edmeadesafe4d802007-06-03 22:07:43 +010051extern WCHAR inbuilt[][10];
Jason Edmeadese37463f2007-03-08 00:37:44 +000052extern int echo_mode, verify_mode, defaultColor;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +010053extern WCHAR quals[MAX_PATH], param1[MAX_PATH], param2[MAX_PATH];
Dave Pickles5f8f4f71999-06-26 10:24:08 +000054extern BATCH_CONTEXT *context;
Dave Picklesebecf502000-08-01 22:02:18 +000055extern DWORD errorlevel;
Dave Pickles74f440e1999-06-06 15:24:04 +000056
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +010057static const WCHAR dotW[] = {'.','\0'};
58static const WCHAR dotdotW[] = {'.','.','\0'};
59static const WCHAR slashW[] = {'\\','\0'};
60static const WCHAR starW[] = {'*','\0'};
61static const WCHAR equalW[] = {'=','\0'};
62static const WCHAR fslashW[] = {'/','\0'};
63static const WCHAR onW[] = {'O','N','\0'};
64static const WCHAR offW[] = {'O','F','F','\0'};
65static const WCHAR parmY[] = {'/','Y','\0'};
66static const WCHAR parmNoY[] = {'/','-','Y','\0'};
67static const WCHAR nullW[] = {'\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +000068
Francois Gougete7b12572009-01-05 19:57:31 +010069/**************************************************************************
70 * WCMD_ask_confirm
71 *
72 * Issue a message and ask 'Are you sure (Y/N)', waiting on a valid
73 * answer.
74 *
75 * Returns True if Y (or A) answer is selected
76 * If optionAll contains a pointer, ALL is allowed, and if answered
77 * set to TRUE
78 *
79 */
80static BOOL WCMD_ask_confirm (WCHAR *message, BOOL showSureText, BOOL *optionAll) {
81
82 WCHAR msgbuffer[MAXSTRING];
83 WCHAR Ybuffer[MAXSTRING];
84 WCHAR Nbuffer[MAXSTRING];
85 WCHAR Abuffer[MAXSTRING];
86 WCHAR answer[MAX_PATH] = {'\0'};
87 DWORD count = 0;
88
89 /* Load the translated 'Are you sure', plus valid answers */
Alexandre Julliard79b00722009-12-09 18:52:40 +010090 LoadStringW(hinst, WCMD_CONFIRM, msgbuffer, sizeof(msgbuffer)/sizeof(WCHAR));
91 LoadStringW(hinst, WCMD_YES, Ybuffer, sizeof(Ybuffer)/sizeof(WCHAR));
92 LoadStringW(hinst, WCMD_NO, Nbuffer, sizeof(Nbuffer)/sizeof(WCHAR));
93 LoadStringW(hinst, WCMD_ALL, Abuffer, sizeof(Abuffer)/sizeof(WCHAR));
Francois Gougete7b12572009-01-05 19:57:31 +010094
95 /* Loop waiting on a Y or N */
96 while (answer[0] != Ybuffer[0] && answer[0] != Nbuffer[0]) {
97 static const WCHAR startBkt[] = {' ','(','\0'};
98 static const WCHAR endBkt[] = {')','?','\0'};
99
100 WCMD_output_asis (message);
101 if (showSureText) {
102 WCMD_output_asis (msgbuffer);
103 }
104 WCMD_output_asis (startBkt);
105 WCMD_output_asis (Ybuffer);
106 WCMD_output_asis (fslashW);
107 WCMD_output_asis (Nbuffer);
108 if (optionAll) {
109 WCMD_output_asis (fslashW);
110 WCMD_output_asis (Abuffer);
111 }
112 WCMD_output_asis (endBkt);
113 WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE), answer,
114 sizeof(answer)/sizeof(WCHAR), &count, NULL);
115 answer[0] = toupperW(answer[0]);
116 }
117
118 /* Return the answer */
119 return ((answer[0] == Ybuffer[0]) ||
120 (optionAll && (answer[0] == Abuffer[0])));
121}
122
Dave Pickles74f440e1999-06-06 15:24:04 +0000123/****************************************************************************
124 * WCMD_clear_screen
125 *
126 * Clear the terminal screen.
127 */
128
Eric Pouechb2f079b2003-02-27 01:41:21 +0000129void WCMD_clear_screen (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000130
Jason Edmeadesa4c214e2002-04-29 17:12:57 +0000131 /* Emulate by filling the screen from the top left to bottom right with
132 spaces, then moving the cursor to the top left afterwards */
Jason Edmeadesa4c214e2002-04-29 17:12:57 +0000133 CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
134 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
Dave Pickles74f440e1999-06-06 15:24:04 +0000135
Eric Pouechb2f079b2003-02-27 01:41:21 +0000136 if (GetConsoleScreenBufferInfo(hStdOut, &consoleInfo))
137 {
138 COORD topLeft;
Mike McCormack516a5772005-08-19 10:04:03 +0000139 DWORD screenSize;
140
Eric Pouechb2f079b2003-02-27 01:41:21 +0000141 screenSize = consoleInfo.dwSize.X * (consoleInfo.dwSize.Y + 1);
Jason Edmeadesa4c214e2002-04-29 17:12:57 +0000142
Eric Pouechb2f079b2003-02-27 01:41:21 +0000143 topLeft.X = 0;
144 topLeft.Y = 0;
Alexandre Julliard79b00722009-12-09 18:52:40 +0100145 FillConsoleOutputCharacterW(hStdOut, ' ', screenSize, topLeft, &screenSize);
Eric Pouechb2f079b2003-02-27 01:41:21 +0000146 SetConsoleCursorPosition(hStdOut, topLeft);
147 }
Dave Pickles74f440e1999-06-06 15:24:04 +0000148}
149
150/****************************************************************************
151 * WCMD_change_tty
152 *
153 * Change the default i/o device (ie redirect STDin/STDout).
154 */
155
Eric Pouechb2f079b2003-02-27 01:41:21 +0000156void WCMD_change_tty (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000157
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100158 WCMD_output (WCMD_LoadMessage(WCMD_NYI));
Dave Pickles74f440e1999-06-06 15:24:04 +0000159
160}
161
162/****************************************************************************
163 * WCMD_copy
164 *
165 * Copy a file or wildcarded set.
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100166 * FIXME: Add support for a+b+c type syntax
Dave Pickles74f440e1999-06-06 15:24:04 +0000167 */
168
Eric Pouechb2f079b2003-02-27 01:41:21 +0000169void WCMD_copy (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000170
Alexandre Julliard79b00722009-12-09 18:52:40 +0100171 WIN32_FIND_DATAW fd;
Alexandre Julliardabfe1052007-03-01 12:43:19 +0100172 HANDLE hff;
173 BOOL force, status;
Andrew Nguyen203c5382009-10-03 17:00:59 -0500174 WCHAR outpath[MAX_PATH], srcpath[MAX_PATH], copycmd[4];
Alexandre Julliardabfe1052007-03-01 12:43:19 +0100175 DWORD len;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100176 static const WCHAR copyCmdW[] = {'C','O','P','Y','C','M','D','\0'};
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100177 BOOL copyToDir = FALSE;
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100178 WCHAR srcspec[MAX_PATH];
179 DWORD attribs;
180 WCHAR drive[10];
181 WCHAR dir[MAX_PATH];
182 WCHAR fname[MAX_PATH];
183 WCHAR ext[MAX_PATH];
Dave Pickles74f440e1999-06-06 15:24:04 +0000184
Markus Amsler765ff5d2006-10-31 21:11:28 +0100185 if (param1[0] == 0x00) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100186 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Markus Amsler765ff5d2006-10-31 21:11:28 +0100187 return;
188 }
189
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100190 /* Convert source into full spec */
191 WINE_TRACE("Copy source (supplied): '%s'\n", wine_dbgstr_w(param1));
Alexandre Julliard79b00722009-12-09 18:52:40 +0100192 GetFullPathNameW(param1, sizeof(srcpath)/sizeof(WCHAR), srcpath, NULL);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100193 if (srcpath[strlenW(srcpath) - 1] == '\\')
194 srcpath[strlenW(srcpath) - 1] = '\0';
195
196 if ((strchrW(srcpath,'*') == NULL) && (strchrW(srcpath,'?') == NULL)) {
Alexandre Julliard79b00722009-12-09 18:52:40 +0100197 attribs = GetFileAttributesW(srcpath);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100198 } else {
199 attribs = 0;
200 }
201 strcpyW(srcspec, srcpath);
202
203 /* If a directory, then add \* on the end when searching */
204 if (attribs & FILE_ATTRIBUTE_DIRECTORY) {
205 strcatW(srcpath, slashW);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100206 strcatW(srcspec, slashW);
207 strcatW(srcspec, starW);
208 } else {
209 WCMD_splitpath(srcpath, drive, dir, fname, ext);
210 strcpyW(srcpath, drive);
211 strcatW(srcpath, dir);
Dave Pickles74f440e1999-06-06 15:24:04 +0000212 }
Jason Edmeades13c51172002-04-20 20:54:38 +0000213
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100214 WINE_TRACE("Copy source (calculated): path: '%s'\n", wine_dbgstr_w(srcpath));
215
Jason Edmeades13c51172002-04-20 20:54:38 +0000216 /* If no destination supplied, assume current directory */
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100217 WINE_TRACE("Copy destination (supplied): '%s'\n", wine_dbgstr_w(param2));
Jason Edmeades13c51172002-04-20 20:54:38 +0000218 if (param2[0] == 0x00) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100219 strcpyW(param2, dotW);
Jason Edmeades13c51172002-04-20 20:54:38 +0000220 }
221
Alexandre Julliard79b00722009-12-09 18:52:40 +0100222 GetFullPathNameW(param2, sizeof(outpath)/sizeof(WCHAR), outpath, NULL);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100223 if (outpath[strlenW(outpath) - 1] == '\\')
224 outpath[strlenW(outpath) - 1] = '\0';
Alexandre Julliard79b00722009-12-09 18:52:40 +0100225 attribs = GetFileAttributesW(outpath);
Dmitry Potapovf918d172007-10-13 04:07:57 +0400226 if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY)) {
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100227 strcatW (outpath, slashW);
228 copyToDir = TRUE;
Dave Picklesebecf502000-08-01 22:02:18 +0000229 }
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100230 WINE_TRACE("Copy destination (calculated): '%s'(%d)\n",
231 wine_dbgstr_w(outpath), copyToDir);
Jason Edmeades13c51172002-04-20 20:54:38 +0000232
Alexander Farberf6ec4412007-02-28 14:49:46 +0100233 /* /-Y has the highest priority, then /Y and finally the COPYCMD env. variable */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100234 if (strstrW (quals, parmNoY))
Alexander Farberf6ec4412007-02-28 14:49:46 +0100235 force = FALSE;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100236 else if (strstrW (quals, parmY))
Alexander Farberf6ec4412007-02-28 14:49:46 +0100237 force = TRUE;
238 else {
Andrew Nguyen203c5382009-10-03 17:00:59 -0500239 /* By default, we will force the overwrite in batch mode and ask for
240 * confirmation in interactive mode. */
241 force = !!context;
242
243 /* If COPYCMD is set, then we force the overwrite with /Y and ask for
244 * confirmation with /-Y. If COPYCMD is neither of those, then we use the
245 * default behavior. */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100246 len = GetEnvironmentVariableW(copyCmdW, copycmd, sizeof(copycmd)/sizeof(WCHAR));
Andrew Nguyen203c5382009-10-03 17:00:59 -0500247 if (len && len < (sizeof(copycmd)/sizeof(WCHAR))) {
248 if (!lstrcmpiW (copycmd, parmY))
249 force = TRUE;
250 else if (!lstrcmpiW (copycmd, parmNoY))
251 force = FALSE;
252 }
Alexander Farberf6ec4412007-02-28 14:49:46 +0100253 }
254
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100255 /* Loop through all source files */
256 WINE_TRACE("Searching for: '%s'\n", wine_dbgstr_w(srcspec));
Alexandre Julliard79b00722009-12-09 18:52:40 +0100257 hff = FindFirstFileW(srcspec, &fd);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100258 if (hff != INVALID_HANDLE_VALUE) {
259 do {
260 WCHAR outname[MAX_PATH];
261 WCHAR srcname[MAX_PATH];
262 BOOL overwrite = force;
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100263
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100264 /* Destination is either supplied filename, or source name in
265 supplied destination directory */
266 strcpyW(outname, outpath);
267 if (copyToDir) strcatW(outname, fd.cFileName);
268 strcpyW(srcname, srcpath);
269 strcatW(srcname, fd.cFileName);
270
271 WINE_TRACE("Copying from : '%s'\n", wine_dbgstr_w(srcname));
272 WINE_TRACE("Copying to : '%s'\n", wine_dbgstr_w(outname));
273
274 /* Skip . and .., and directories */
275 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
276 overwrite = FALSE;
277 WINE_TRACE("Skipping directories\n");
278 }
279
280 /* Prompt before overwriting */
281 else if (!overwrite) {
Alexandre Julliard79b00722009-12-09 18:52:40 +0100282 attribs = GetFileAttributesW(outname);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100283 if (attribs != INVALID_FILE_ATTRIBUTES) {
284 WCHAR buffer[MAXSTRING];
Alexandre Julliard79b00722009-12-09 18:52:40 +0100285 wsprintfW(buffer, WCMD_LoadMessage(WCMD_OVERWRITE), outname);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100286 overwrite = WCMD_ask_confirm(buffer, FALSE, NULL);
287 }
288 else overwrite = TRUE;
289 }
290
291 /* Do the copy as appropriate */
292 if (overwrite) {
Alexandre Julliard79b00722009-12-09 18:52:40 +0100293 status = CopyFileW(srcname, outname, FALSE);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100294 if (!status) WCMD_print_error ();
295 }
296
Alexandre Julliard79b00722009-12-09 18:52:40 +0100297 } while (FindNextFileW(hff, &fd) != 0);
Dave Pickles74f440e1999-06-06 15:24:04 +0000298 FindClose (hff);
Jason Edmeadesa766ba02007-07-27 21:43:37 +0100299 } else {
300 status = ERROR_FILE_NOT_FOUND;
301 WCMD_print_error ();
Dave Pickles74f440e1999-06-06 15:24:04 +0000302 }
303}
304
305/****************************************************************************
306 * WCMD_create_dir
307 *
308 * Create a directory.
Aric Stewart1d5adff2005-12-03 18:02:15 +0100309 *
Francois Gouget8a18e0e2008-04-07 13:01:02 +0200310 * this works recursively. so mkdir dir1\dir2\dir3 will create dir1 and dir2 if
Aric Stewart1d5adff2005-12-03 18:02:15 +0100311 * they do not already exist.
Dave Pickles74f440e1999-06-06 15:24:04 +0000312 */
313
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100314static BOOL create_full_path(WCHAR* path)
Aric Stewart1d5adff2005-12-03 18:02:15 +0100315{
316 int len;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100317 WCHAR *new_path;
Aric Stewart1d5adff2005-12-03 18:02:15 +0100318 BOOL ret = TRUE;
319
Dan Kegel15998c22010-02-02 17:42:01 -0800320 new_path = HeapAlloc(GetProcessHeap(),0,(strlenW(path)+1) * sizeof(WCHAR));
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100321 strcpyW(new_path,path);
Aric Stewart1d5adff2005-12-03 18:02:15 +0100322
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100323 while ((len = strlenW(new_path)) && new_path[len - 1] == '\\')
Aric Stewart1d5adff2005-12-03 18:02:15 +0100324 new_path[len - 1] = 0;
325
Alexandre Julliard79b00722009-12-09 18:52:40 +0100326 while (!CreateDirectoryW(new_path,NULL))
Aric Stewart1d5adff2005-12-03 18:02:15 +0100327 {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100328 WCHAR *slash;
Aric Stewart1d5adff2005-12-03 18:02:15 +0100329 DWORD last_error = GetLastError();
330 if (last_error == ERROR_ALREADY_EXISTS)
331 break;
332
333 if (last_error != ERROR_PATH_NOT_FOUND)
334 {
335 ret = FALSE;
336 break;
337 }
338
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100339 if (!(slash = strrchrW(new_path,'\\')) && ! (slash = strrchrW(new_path,'/')))
Aric Stewart1d5adff2005-12-03 18:02:15 +0100340 {
341 ret = FALSE;
342 break;
343 }
344
345 len = slash - new_path;
346 new_path[len] = 0;
347 if (!create_full_path(new_path))
348 {
349 ret = FALSE;
350 break;
351 }
352 new_path[len] = '\\';
353 }
354 HeapFree(GetProcessHeap(),0,new_path);
355 return ret;
356}
357
Eric Pouechb2f079b2003-02-27 01:41:21 +0000358void WCMD_create_dir (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000359
Markus Amsler765ff5d2006-10-31 21:11:28 +0100360 if (param1[0] == 0x00) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100361 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Markus Amsler765ff5d2006-10-31 21:11:28 +0100362 return;
363 }
Aric Stewart1d5adff2005-12-03 18:02:15 +0100364 if (!create_full_path(param1)) WCMD_print_error ();
Dave Pickles74f440e1999-06-06 15:24:04 +0000365}
366
367/****************************************************************************
368 * WCMD_delete
369 *
370 * Delete a file or wildcarded set.
371 *
Jason Edmeadesb822e732007-02-27 23:20:55 +0000372 * Note on /A:
373 * - Testing shows /A is repeatable, eg. /a-r /ar matches all files
374 * - Each set is a pattern, eg /ahr /as-r means
375 * readonly+hidden OR nonreadonly system files
376 * - The '-' applies to a single field, ie /a:-hr means read only
377 * non-hidden files
Dave Pickles74f440e1999-06-06 15:24:04 +0000378 */
379
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100380BOOL WCMD_delete (WCHAR *command, BOOL expectDir) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000381
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000382 int argno = 0;
383 int argsProcessed = 0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100384 WCHAR *argN = command;
Jason Edmeades68b11d12007-04-23 23:24:38 +0100385 BOOL foundAny = FALSE;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100386 static const WCHAR parmA[] = {'/','A','\0'};
387 static const WCHAR parmQ[] = {'/','Q','\0'};
388 static const WCHAR parmP[] = {'/','P','\0'};
389 static const WCHAR parmS[] = {'/','S','\0'};
390 static const WCHAR parmF[] = {'/','F','\0'};
Jason Edmeades68b11d12007-04-23 23:24:38 +0100391
392 /* If not recursing, clear error flag */
393 if (expectDir) errorlevel = 0;
Dave Pickles74f440e1999-06-06 15:24:04 +0000394
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000395 /* Loop through all args */
396 while (argN) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100397 WCHAR *thisArg = WCMD_parameter (command, argno++, &argN);
398 WCHAR argCopy[MAX_PATH];
Jason Edmeades68b11d12007-04-23 23:24:38 +0100399
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000400 if (argN && argN[0] != '/') {
Jason Edmeades409368e2007-02-27 23:19:24 +0000401
Alexandre Julliard79b00722009-12-09 18:52:40 +0100402 WIN32_FIND_DATAW fd;
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000403 HANDLE hff;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100404 WCHAR fpath[MAX_PATH];
405 WCHAR *p;
Jason Edmeades68b11d12007-04-23 23:24:38 +0100406 BOOL handleParm = TRUE;
407 BOOL found = FALSE;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100408 static const WCHAR anyExt[]= {'.','*','\0'};
Jason Edmeades409368e2007-02-27 23:19:24 +0000409
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100410 strcpyW(argCopy, thisArg);
411 WINE_TRACE("del: Processing arg %s (quals:%s)\n",
412 wine_dbgstr_w(argCopy), wine_dbgstr_w(quals));
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000413 argsProcessed++;
Jason Edmeades409368e2007-02-27 23:19:24 +0000414
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000415 /* If filename part of parameter is * or *.*, prompt unless
416 /Q supplied. */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100417 if ((strstrW (quals, parmQ) == NULL) && (strstrW (quals, parmP) == NULL)) {
Jason Edmeades409368e2007-02-27 23:19:24 +0000418
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100419 WCHAR drive[10];
420 WCHAR dir[MAX_PATH];
421 WCHAR fname[MAX_PATH];
422 WCHAR ext[MAX_PATH];
Jason Edmeades409368e2007-02-27 23:19:24 +0000423
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000424 /* Convert path into actual directory spec */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100425 GetFullPathNameW(argCopy, sizeof(fpath)/sizeof(WCHAR), fpath, NULL);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000426 WCMD_splitpath(fpath, drive, dir, fname, ext);
Jason Edmeades409368e2007-02-27 23:19:24 +0000427
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000428 /* Only prompt for * and *.*, not *a, a*, *.a* etc */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100429 if ((strcmpW(fname, starW) == 0) &&
430 (*ext == 0x00 || (strcmpW(ext, anyExt) == 0))) {
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000431 BOOL ok;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100432 WCHAR question[MAXSTRING];
433 static const WCHAR fmt[] = {'%','s',' ','\0'};
Jason Edmeades10c3764d2007-02-27 23:20:25 +0000434
Jason Edmeades68b11d12007-04-23 23:24:38 +0100435 /* Note: Flag as found, to avoid file not found message */
436 found = TRUE;
437
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000438 /* Ask for confirmation */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100439 wsprintfW(question, fmt, fpath);
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100440 ok = WCMD_ask_confirm(question, TRUE, NULL);
Jason Edmeades10c3764d2007-02-27 23:20:25 +0000441
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000442 /* Abort if answer is 'N' */
443 if (!ok) continue;
444 }
445 }
Jason Edmeadesb822e732007-02-27 23:20:55 +0000446
Jason Edmeades68b11d12007-04-23 23:24:38 +0100447 /* First, try to delete in the current directory */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100448 hff = FindFirstFileW(argCopy, &fd);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000449 if (hff == INVALID_HANDLE_VALUE) {
Jason Edmeades68b11d12007-04-23 23:24:38 +0100450 handleParm = FALSE;
451 } else {
452 found = TRUE;
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000453 }
Jason Edmeades68b11d12007-04-23 23:24:38 +0100454
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000455 /* Support del <dirname> by just deleting all files dirname\* */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100456 if (handleParm && (strchrW(argCopy,'*') == NULL) && (strchrW(argCopy,'?') == NULL)
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000457 && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100458 WCHAR modifiedParm[MAX_PATH];
459 static const WCHAR slashStar[] = {'\\','*','\0'};
460
461 strcpyW(modifiedParm, argCopy);
462 strcatW(modifiedParm, slashStar);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000463 FindClose(hff);
Jason Edmeades68b11d12007-04-23 23:24:38 +0100464 found = TRUE;
465 WCMD_delete(modifiedParm, FALSE);
Jason Edmeadesb822e732007-02-27 23:20:55 +0000466
Jason Edmeades68b11d12007-04-23 23:24:38 +0100467 } else if (handleParm) {
Jason Edmeadesb822e732007-02-27 23:20:55 +0000468
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000469 /* Build the filename to delete as <supplied directory>\<findfirst filename> */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100470 strcpyW (fpath, argCopy);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000471 do {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100472 p = strrchrW (fpath, '\\');
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000473 if (p != NULL) {
474 *++p = '\0';
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100475 strcatW (fpath, fd.cFileName);
Jason Edmeadesb822e732007-02-27 23:20:55 +0000476 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100477 else strcpyW (fpath, fd.cFileName);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000478 if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
479 BOOL ok = TRUE;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100480 WCHAR *nextA = strstrW (quals, parmA);
Jason Edmeadesb822e732007-02-27 23:20:55 +0000481
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000482 /* Handle attribute matching (/A) */
483 if (nextA != NULL) {
484 ok = FALSE;
485 while (nextA != NULL && !ok) {
Jason Edmeadesb822e732007-02-27 23:20:55 +0000486
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100487 WCHAR *thisA = (nextA+2);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000488 BOOL stillOK = TRUE;
489
490 /* Skip optional : */
491 if (*thisA == ':') thisA++;
492
493 /* Parse each of the /A[:]xxx in turn */
494 while (*thisA && *thisA != '/') {
495 BOOL negate = FALSE;
496 BOOL attribute = FALSE;
497
498 /* Match negation of attribute first */
499 if (*thisA == '-') {
500 negate=TRUE;
501 thisA++;
502 }
503
504 /* Match attribute */
505 switch (*thisA) {
506 case 'R': attribute = (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY);
507 break;
508 case 'H': attribute = (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
509 break;
510 case 'S': attribute = (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM);
511 break;
512 case 'A': attribute = (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE);
513 break;
514 default:
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100515 WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000516 }
517
518 /* Now check result, keeping a running boolean about whether it
Francois Gouget8a18e0e2008-04-07 13:01:02 +0200519 matches all parsed attributes so far */
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000520 if (attribute && !negate) {
521 stillOK = stillOK;
522 } else if (!attribute && negate) {
523 stillOK = stillOK;
524 } else {
525 stillOK = FALSE;
526 }
527 thisA++;
528 }
529
530 /* Save the running total as the final result */
531 ok = stillOK;
532
533 /* Step on to next /A set */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100534 nextA = strstrW (nextA+1, parmA);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000535 }
536 }
537
538 /* /P means prompt for each file */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100539 if (ok && strstrW (quals, parmP) != NULL) {
540 WCHAR question[MAXSTRING];
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000541
542 /* Ask for confirmation */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100543 wsprintfW(question, WCMD_LoadMessage(WCMD_DELPROMPT), fpath);
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100544 ok = WCMD_ask_confirm(question, FALSE, NULL);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000545 }
546
547 /* Only proceed if ok to */
548 if (ok) {
549
550 /* If file is read only, and /F supplied, delete it */
551 if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY &&
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100552 strstrW (quals, parmF) != NULL) {
Alexandre Julliard79b00722009-12-09 18:52:40 +0100553 SetFileAttributesW(fpath, fd.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000554 }
555
556 /* Now do the delete */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100557 if (!DeleteFileW(fpath)) WCMD_print_error ();
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000558 }
559
560 }
Alexandre Julliard79b00722009-12-09 18:52:40 +0100561 } while (FindNextFileW(hff, &fd) != 0);
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000562 FindClose (hff);
Jason Edmeadesb822e732007-02-27 23:20:55 +0000563 }
Jason Edmeades68b11d12007-04-23 23:24:38 +0100564
Francois Gouget5a8fc342007-04-30 02:06:11 +0200565 /* Now recurse into all subdirectories handling the parameter in the same way */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100566 if (strstrW (quals, parmS) != NULL) {
Jason Edmeades68b11d12007-04-23 23:24:38 +0100567
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100568 WCHAR thisDir[MAX_PATH];
Jason Edmeades68b11d12007-04-23 23:24:38 +0100569 int cPos;
570
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100571 WCHAR drive[10];
572 WCHAR dir[MAX_PATH];
573 WCHAR fname[MAX_PATH];
574 WCHAR ext[MAX_PATH];
Jason Edmeades68b11d12007-04-23 23:24:38 +0100575
576 /* Convert path into actual directory spec */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100577 GetFullPathNameW(argCopy, sizeof(thisDir)/sizeof(WCHAR), thisDir, NULL);
Jason Edmeades68b11d12007-04-23 23:24:38 +0100578 WCMD_splitpath(thisDir, drive, dir, fname, ext);
579
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100580 strcpyW(thisDir, drive);
581 strcatW(thisDir, dir);
582 cPos = strlenW(thisDir);
Jason Edmeades68b11d12007-04-23 23:24:38 +0100583
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100584 WINE_TRACE("Searching recursively in '%s'\n", wine_dbgstr_w(thisDir));
Jason Edmeades68b11d12007-04-23 23:24:38 +0100585
586 /* Append '*' to the directory */
587 thisDir[cPos] = '*';
588 thisDir[cPos+1] = 0x00;
589
Alexandre Julliard79b00722009-12-09 18:52:40 +0100590 hff = FindFirstFileW(thisDir, &fd);
Jason Edmeades68b11d12007-04-23 23:24:38 +0100591
592 /* Remove residual '*' */
593 thisDir[cPos] = 0x00;
594
595 if (hff != INVALID_HANDLE_VALUE) {
596 DIRECTORY_STACK *allDirs = NULL;
597 DIRECTORY_STACK *lastEntry = NULL;
598
599 do {
600 if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100601 (strcmpW(fd.cFileName, dotdotW) != 0) &&
602 (strcmpW(fd.cFileName, dotW) != 0)) {
Jason Edmeades68b11d12007-04-23 23:24:38 +0100603
604 DIRECTORY_STACK *nextDir;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100605 WCHAR subParm[MAX_PATH];
Jason Edmeades68b11d12007-04-23 23:24:38 +0100606
607 /* Work out search parameter in sub dir */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100608 strcpyW (subParm, thisDir);
609 strcatW (subParm, fd.cFileName);
610 strcatW (subParm, slashW);
611 strcatW (subParm, fname);
612 strcatW (subParm, ext);
613 WINE_TRACE("Recursive, Adding to search list '%s'\n", wine_dbgstr_w(subParm));
Jason Edmeades68b11d12007-04-23 23:24:38 +0100614
615 /* Allocate memory, add to list */
Michael Stefaniuc6519a832007-06-27 00:12:22 +0200616 nextDir = HeapAlloc(GetProcessHeap(),0,sizeof(DIRECTORY_STACK));
Jason Edmeades68b11d12007-04-23 23:24:38 +0100617 if (allDirs == NULL) allDirs = nextDir;
618 if (lastEntry != NULL) lastEntry->next = nextDir;
619 lastEntry = nextDir;
620 nextDir->next = NULL;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100621 nextDir->dirName = HeapAlloc(GetProcessHeap(),0,
622 (strlenW(subParm)+1) * sizeof(WCHAR));
623 strcpyW(nextDir->dirName, subParm);
Jason Edmeades68b11d12007-04-23 23:24:38 +0100624 }
Alexandre Julliard79b00722009-12-09 18:52:40 +0100625 } while (FindNextFileW(hff, &fd) != 0);
Jason Edmeades68b11d12007-04-23 23:24:38 +0100626 FindClose (hff);
627
628 /* Go through each subdir doing the delete */
629 while (allDirs != NULL) {
630 DIRECTORY_STACK *tempDir;
631
632 tempDir = allDirs->next;
633 found |= WCMD_delete (allDirs->dirName, FALSE);
634
635 HeapFree(GetProcessHeap(),0,allDirs->dirName);
636 HeapFree(GetProcessHeap(),0,allDirs);
637 allDirs = tempDir;
638 }
639 }
640 }
641 /* Keep running total to see if any found, and if not recursing
642 issue error message */
643 if (expectDir) {
644 if (!found) {
645 errorlevel = 1;
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100646 WCMD_output (WCMD_LoadMessage(WCMD_FILENOTFOUND), argCopy);
Jason Edmeades68b11d12007-04-23 23:24:38 +0100647 }
648 }
649 foundAny |= found;
Dave Pickles74f440e1999-06-06 15:24:04 +0000650 }
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000651 }
652
653 /* Handle no valid args */
654 if (argsProcessed == 0) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +0100655 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Jason Edmeadesa97d1202007-03-04 22:35:09 +0000656 }
Jason Edmeades68b11d12007-04-23 23:24:38 +0100657
658 return foundAny;
Dave Pickles74f440e1999-06-06 15:24:04 +0000659}
660
661/****************************************************************************
662 * WCMD_echo
663 *
664 * Echo input to the screen (or not). We don't try to emulate the bugs
665 * in DOS (try typing "ECHO ON AGAIN" for an example).
666 */
667
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100668void WCMD_echo (const WCHAR *command) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000669
Alexandre Julliardabfe1052007-03-01 12:43:19 +0100670 int count;
Dave Pickles74f440e1999-06-06 15:24:04 +0000671
Mike McCormack8d020102004-03-18 04:01:32 +0000672 if ((command[0] == '.') && (command[1] == 0)) {
673 WCMD_output (newline);
674 return;
675 }
676 if (command[0]==' ')
677 command++;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100678 count = strlenW(command);
Dave Pickles74f440e1999-06-06 15:24:04 +0000679 if (count == 0) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100680 if (echo_mode) WCMD_output (WCMD_LoadMessage(WCMD_ECHOPROMPT), onW);
681 else WCMD_output (WCMD_LoadMessage(WCMD_ECHOPROMPT), offW);
Dave Pickles74f440e1999-06-06 15:24:04 +0000682 return;
683 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100684 if (lstrcmpiW(command, onW) == 0) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000685 echo_mode = 1;
686 return;
687 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +0100688 if (lstrcmpiW(command, offW) == 0) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000689 echo_mode = 0;
690 return;
691 }
Vincent Béron9a624912002-05-31 23:06:46 +0000692 WCMD_output_asis (command);
Dave Pickles74f440e1999-06-06 15:24:04 +0000693 WCMD_output (newline);
694
695}
696
Dave Pickles036a9f71999-07-10 11:36:45 +0000697/**************************************************************************
Dave Pickles74f440e1999-06-06 15:24:04 +0000698 * WCMD_for
699 *
700 * Batch file loop processing.
Jason Edmeades54d890c2007-06-15 20:59:28 +0100701 *
702 * On entry: cmdList contains the syntax up to the set
703 * next cmdList and all in that bracket contain the set data
704 * next cmdlist contains the DO cmd
705 * following that is either brackets or && entries (as per if)
706 *
Dave Pickles74f440e1999-06-06 15:24:04 +0000707 */
708
Jason Edmeades8f12d8b2007-06-15 20:59:21 +0100709void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
Dave Pickles74f440e1999-06-06 15:24:04 +0000710
Alexandre Julliard79b00722009-12-09 18:52:40 +0100711 WIN32_FIND_DATAW fd;
Alexandre Julliardabfe1052007-03-01 12:43:19 +0100712 HANDLE hff;
Alexandre Julliardabfe1052007-03-01 12:43:19 +0100713 int i;
Jason Edmeadesdc372172007-09-11 21:43:02 +0100714 const WCHAR inW[] = {'i', 'n', ' ', '\0'};
715 const WCHAR doW[] = {'d', 'o', ' ', '\0'};
Jason Edmeades54d890c2007-06-15 20:59:28 +0100716 CMD_LIST *setStart, *thisSet, *cmdStart, *cmdEnd;
717 WCHAR variable[4];
718 WCHAR *firstCmd;
719 int thisDepth;
Dave Pickles036a9f71999-07-10 11:36:45 +0000720
Jason Edmeadesdc372172007-09-11 21:43:02 +0100721 WCHAR *curPos = p;
722 BOOL expandDirs = FALSE;
723 BOOL useNumbers = FALSE;
Jason Edmeadesdc372172007-09-11 21:43:02 +0100724 BOOL doFileset = FALSE;
725 LONG numbers[3] = {0,0,0}; /* Defaults to 0 in native */
726 int itemNum;
727 CMD_LIST *thisCmdStart;
728
729
730 /* Handle optional qualifiers (multiple are allowed) */
731 while (*curPos && *curPos == '/') {
732 WINE_TRACE("Processing qualifier at %s\n", wine_dbgstr_w(curPos));
733 curPos++;
734 switch (toupperW(*curPos)) {
735 case 'D': curPos++; expandDirs = TRUE; break;
736 case 'L': curPos++; useNumbers = TRUE; break;
737
738 /* Recursive is special case - /R can have an optional path following it */
739 /* filenamesets are another special case - /F can have an optional options following it */
740 case 'R':
741 case 'F':
742 {
743 BOOL isRecursive = (*curPos == 'R');
744
Gerald Pfeifer02a0bd32010-05-01 16:24:45 +0200745 if (!isRecursive)
746 doFileset = TRUE;
Jason Edmeadesdc372172007-09-11 21:43:02 +0100747
748 /* Skip whitespace */
749 curPos++;
750 while (*curPos && *curPos==' ') curPos++;
751
752 /* Next parm is either qualifier, path/options or variable -
753 only care about it if it is the path/options */
754 if (*curPos && *curPos != '/' && *curPos != '%') {
755 if (isRecursive) WINE_FIXME("/R needs to handle supplied root\n");
756 else WINE_FIXME("/F needs to handle options\n");
757 }
758 break;
759 }
760 default:
761 WINE_FIXME("for qualifier '%c' unhandled\n", *curPos);
762 curPos++;
763 }
764
765 /* Skip whitespace between qualifiers */
766 while (*curPos && *curPos==' ') curPos++;
767 }
768
769 /* Skip whitespace before variable */
770 while (*curPos && *curPos==' ') curPos++;
771
772 /* Ensure line continues with variable */
773 if (!*curPos || *curPos != '%') {
774 WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
775 return;
776 }
777
778 /* Variable should follow */
779 i = 0;
780 while (curPos[i] && curPos[i]!=' ') i++;
781 memcpy(&variable[0], curPos, i*sizeof(WCHAR));
782 variable[i] = 0x00;
783 WINE_TRACE("Variable identified as %s\n", wine_dbgstr_w(variable));
784 curPos = &curPos[i];
785
786 /* Skip whitespace before IN */
787 while (*curPos && *curPos==' ') curPos++;
788
789 /* Ensure line continues with IN */
790 if (!*curPos || lstrcmpiW (curPos, inW)) {
791 WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
792 return;
Dave Pickles5f8f4f71999-06-26 10:24:08 +0000793 }
Dave Pickles74f440e1999-06-06 15:24:04 +0000794
Jason Edmeades54d890c2007-06-15 20:59:28 +0100795 /* Save away where the set of data starts and the variable */
Jason Edmeades54d890c2007-06-15 20:59:28 +0100796 thisDepth = (*cmdList)->bracketDepth;
797 *cmdList = (*cmdList)->nextcommand;
798 setStart = (*cmdList);
Dave Pickles036a9f71999-07-10 11:36:45 +0000799
Jason Edmeades54d890c2007-06-15 20:59:28 +0100800 /* Skip until the close bracket */
801 WINE_TRACE("Searching %p as the set\n", *cmdList);
802 while (*cmdList &&
803 (*cmdList)->command != NULL &&
804 (*cmdList)->bracketDepth > thisDepth) {
805 WINE_TRACE("Skipping %p which is part of the set\n", *cmdList);
806 *cmdList = (*cmdList)->nextcommand;
Dave Pickles036a9f71999-07-10 11:36:45 +0000807 }
Jason Edmeades54d890c2007-06-15 20:59:28 +0100808
809 /* Skip the close bracket, if there is one */
810 if (*cmdList) *cmdList = (*cmdList)->nextcommand;
811
812 /* Syntax error if missing close bracket, or nothing following it
813 and once we have the complete set, we expect a DO */
814 WINE_TRACE("Looking for 'do' in %p\n", *cmdList);
815 if ((*cmdList == NULL) ||
Alexandre Julliard79b00722009-12-09 18:52:40 +0100816 (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
Jason Edmeades54d890c2007-06-15 20:59:28 +0100817 (*cmdList)->command, 3, doW, -1) != 2)) {
818 WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
819 return;
820 }
821
822 /* Save away the starting position for the commands (and offset for the
823 first one */
824 cmdStart = *cmdList;
825 cmdEnd = *cmdList;
826 firstCmd = (*cmdList)->command + 3; /* Skip 'do ' */
Jason Edmeadesdc372172007-09-11 21:43:02 +0100827 itemNum = 0;
Jason Edmeades54d890c2007-06-15 20:59:28 +0100828
829 thisSet = setStart;
830 /* Loop through all set entries */
831 while (thisSet &&
832 thisSet->command != NULL &&
833 thisSet->bracketDepth >= thisDepth) {
834
835 /* Loop through all entries on the same line */
836 WCHAR *item;
Jason Edmeadesf3ae48c2007-09-11 21:43:06 +0100837 WCHAR *itemStart;
Jason Edmeades54d890c2007-06-15 20:59:28 +0100838
839 WINE_TRACE("Processing for set %p\n", thisSet);
840 i = 0;
Jason Edmeadesf3ae48c2007-09-11 21:43:06 +0100841 while (*(item = WCMD_parameter (thisSet->command, i, &itemStart))) {
Jason Edmeades54d890c2007-06-15 20:59:28 +0100842
843 /*
844 * If the parameter within the set has a wildcard then search for matching files
845 * otherwise do a literal substitution.
846 */
847 static const WCHAR wildcards[] = {'*','?','\0'};
Jason Edmeadesdc372172007-09-11 21:43:02 +0100848 thisCmdStart = cmdStart;
Jason Edmeades54d890c2007-06-15 20:59:28 +0100849
Jason Edmeadesdc372172007-09-11 21:43:02 +0100850 itemNum++;
851 WINE_TRACE("Processing for item %d '%s'\n", itemNum, wine_dbgstr_w(item));
852
853 if (!useNumbers && !doFileset) {
854 if (strpbrkW (item, wildcards)) {
Alexandre Julliard79b00722009-12-09 18:52:40 +0100855 hff = FindFirstFileW(item, &fd);
Jason Edmeadesdc372172007-09-11 21:43:02 +0100856 if (hff != INVALID_HANDLE_VALUE) {
857 do {
858 BOOL isDirectory = FALSE;
859
860 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) isDirectory = TRUE;
861
862 /* Handle as files or dirs appropriately, but ignore . and .. */
863 if (isDirectory == expandDirs &&
864 (strcmpW(fd.cFileName, dotdotW) != 0) &&
865 (strcmpW(fd.cFileName, dotW) != 0))
866 {
867 thisCmdStart = cmdStart;
868 WINE_TRACE("Processing FOR filename %s\n", wine_dbgstr_w(fd.cFileName));
869 WCMD_part_execute (&thisCmdStart, firstCmd, variable,
870 fd.cFileName, FALSE, TRUE);
871 }
872
Alexandre Julliard79b00722009-12-09 18:52:40 +0100873 } while (FindNextFileW(hff, &fd) != 0);
Jason Edmeadesdc372172007-09-11 21:43:02 +0100874 FindClose (hff);
Jason Edmeades196fb102007-06-15 20:59:29 +0100875 }
Jason Edmeadesdc372172007-09-11 21:43:02 +0100876 } else {
877 WCMD_part_execute(&thisCmdStart, firstCmd, variable, item, FALSE, TRUE);
878 }
Jason Edmeades54d890c2007-06-15 20:59:28 +0100879
Jason Edmeadesdc372172007-09-11 21:43:02 +0100880 } else if (useNumbers) {
881 /* Convert the first 3 numbers to signed longs and save */
882 if (itemNum <=3) numbers[itemNum-1] = atolW(item);
883 /* else ignore them! */
884
Jason Edmeadesf3ae48c2007-09-11 21:43:06 +0100885 /* Filesets - either a list of files, or a command to run and parse the output */
886 } else if (doFileset && *itemStart != '"') {
Jason Edmeadesdc372172007-09-11 21:43:02 +0100887
888 HANDLE input;
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100889 WCHAR temp_file[MAX_PATH];
Jason Edmeadesdc372172007-09-11 21:43:02 +0100890
891 WINE_TRACE("Processing for filespec from item %d '%s'\n", itemNum,
892 wine_dbgstr_w(item));
893
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100894 /* If backquote or single quote, we need to launch that command
895 and parse the results - use a temporary file */
896 if (*itemStart == '`' || *itemStart == '\'') {
Jason Edmeadesdc372172007-09-11 21:43:02 +0100897
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100898 WCHAR temp_path[MAX_PATH], temp_cmd[MAXSTRING];
Jason Edmeades1ee75382007-09-11 21:43:08 +0100899 static const WCHAR redirOut[] = {'>','%','s','\0'};
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100900 static const WCHAR cmdW[] = {'C','M','D','\0'};
901
902 /* Remove trailing character */
903 itemStart[strlenW(itemStart)-1] = 0x00;
904
905 /* Get temp filename */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100906 GetTempPathW(sizeof(temp_path)/sizeof(WCHAR), temp_path);
907 GetTempFileNameW(temp_path, cmdW, 0, temp_file);
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100908
909 /* Execute program and redirect output */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100910 wsprintfW(temp_cmd, redirOut, (itemStart+1), temp_file);
Jason Edmeades1ee75382007-09-11 21:43:08 +0100911 WCMD_execute (itemStart, temp_cmd, NULL, NULL, NULL);
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100912
913 /* Open the file, read line by line and process */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100914 input = CreateFileW(temp_file, GENERIC_READ, FILE_SHARE_READ,
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100915 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
916 } else {
917
918 /* Open the file, read line by line and process */
Alexandre Julliard79b00722009-12-09 18:52:40 +0100919 input = CreateFileW(item, GENERIC_READ, FILE_SHARE_READ,
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100920 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
921 }
922
923 /* Process the input file */
Jason Edmeadesdc372172007-09-11 21:43:02 +0100924 if (input == INVALID_HANDLE_VALUE) {
925 WCMD_print_error ();
926 WCMD_output (WCMD_LoadMessage(WCMD_READFAIL), item);
927 errorlevel = 1;
928 return; /* FOR loop aborts at first failure here */
929
930 } else {
931
932 WCHAR buffer[MAXSTRING] = {'\0'};
933 WCHAR *where, *parm;
934
935 while (WCMD_fgets (buffer, sizeof(buffer)/sizeof(WCHAR), input)) {
936
937 /* Skip blank lines*/
938 parm = WCMD_parameter (buffer, 0, &where);
939 WINE_TRACE("Parsed parameter: %s from %s\n", wine_dbgstr_w(parm),
940 wine_dbgstr_w(buffer));
941
942 if (where) {
Jason Edmeadesf3ae48c2007-09-11 21:43:06 +0100943 /* FIXME: The following should be moved into its own routine and
944 reused for the string literal parsing below */
Jason Edmeadesdc372172007-09-11 21:43:02 +0100945 thisCmdStart = cmdStart;
946 WCMD_part_execute(&thisCmdStart, firstCmd, variable, parm, FALSE, TRUE);
947 cmdEnd = thisCmdStart;
948 }
949
950 buffer[0] = 0x00;
951
952 }
953 CloseHandle (input);
954 }
Jason Edmeadesf3ae48c2007-09-11 21:43:06 +0100955
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100956 /* Delete the temporary file */
957 if (*itemStart == '`' || *itemStart == '\'') {
Alexandre Julliard79b00722009-12-09 18:52:40 +0100958 DeleteFileW(temp_file);
Jason Edmeadesc7b88e92007-09-11 21:43:07 +0100959 }
960
Jason Edmeadesf3ae48c2007-09-11 21:43:06 +0100961 /* Filesets - A string literal */
962 } else if (doFileset && *itemStart == '"') {
963 WCHAR buffer[MAXSTRING] = {'\0'};
964 WCHAR *where, *parm;
965
966 /* Skip blank lines, and re-extract parameter now string has quotes removed */
967 strcpyW(buffer, item);
968 parm = WCMD_parameter (buffer, 0, &where);
969 WINE_TRACE("Parsed parameter: %s from %s\n", wine_dbgstr_w(parm),
970 wine_dbgstr_w(buffer));
971
972 if (where) {
973 /* FIXME: The following should be moved into its own routine and
974 reused for the string literal parsing below */
975 thisCmdStart = cmdStart;
976 WCMD_part_execute(&thisCmdStart, firstCmd, variable, parm, FALSE, TRUE);
977 cmdEnd = thisCmdStart;
978 }
Jason Edmeades54d890c2007-06-15 20:59:28 +0100979 }
980
981 WINE_TRACE("Post-command, cmdEnd = %p\n", cmdEnd);
982 cmdEnd = thisCmdStart;
983 i++;
984 }
985
986 /* Move onto the next set line */
987 thisSet = thisSet->nextcommand;
988 }
989
Jason Edmeadesdc372172007-09-11 21:43:02 +0100990 /* If /L is provided, now run the for loop */
991 if (useNumbers) {
992 WCHAR thisNum[20];
993 static const WCHAR fmt[] = {'%','d','\0'};
994
995 WINE_TRACE("FOR /L provided range from %d to %d step %d\n",
996 numbers[0], numbers[2], numbers[1]);
997 for (i=numbers[0];
998 (numbers[1]<0)? i>numbers[2] : i<numbers[2];
999 i=i + numbers[1]) {
1000
1001 sprintfW(thisNum, fmt, i);
1002 WINE_TRACE("Processing FOR number %s\n", wine_dbgstr_w(thisNum));
1003
1004 thisCmdStart = cmdStart;
1005 WCMD_part_execute(&thisCmdStart, firstCmd, variable, thisNum, FALSE, TRUE);
1006 cmdEnd = thisCmdStart;
1007 }
1008 }
1009
Jason Edmeades54d890c2007-06-15 20:59:28 +01001010 /* When the loop ends, either something like a GOTO or EXIT /b has terminated
1011 all processing, OR it should be pointing to the end of && processing OR
1012 it should be pointing at the NULL end of bracket for the DO. The return
1013 value needs to be the NEXT command to execute, which it either is, or
1014 we need to step over the closing bracket */
1015 *cmdList = cmdEnd;
1016 if (cmdEnd && cmdEnd->command == NULL) *cmdList = cmdEnd->nextcommand;
1017}
1018
1019
1020/*****************************************************************************
1021 * WCMD_part_execute
1022 *
1023 * Execute a command, and any && or bracketed follow on to the command. The
1024 * first command to be executed may not be at the front of the
Jason Edmeades8e089832007-07-27 21:43:38 +01001025 * commands->thiscommand string (eg. it may point after a DO or ELSE)
Jason Edmeades54d890c2007-06-15 20:59:28 +01001026 */
1027void WCMD_part_execute(CMD_LIST **cmdList, WCHAR *firstcmd, WCHAR *variable,
1028 WCHAR *value, BOOL isIF, BOOL conditionTRUE) {
1029
1030 CMD_LIST *curPosition = *cmdList;
1031 int myDepth = (*cmdList)->bracketDepth;
1032
1033 WINE_TRACE("cmdList(%p), firstCmd(%p), with '%s'='%s', doIt(%d)\n",
1034 cmdList, wine_dbgstr_w(firstcmd),
1035 wine_dbgstr_w(variable), wine_dbgstr_w(value),
1036 conditionTRUE);
1037
1038 /* Skip leading whitespace between condition and the command */
1039 while (firstcmd && *firstcmd && (*firstcmd==' ' || *firstcmd=='\t')) firstcmd++;
1040
1041 /* Process the first command, if there is one */
1042 if (conditionTRUE && firstcmd && *firstcmd) {
1043 WCHAR *command = WCMD_strdupW(firstcmd);
Jason Edmeades1ee75382007-09-11 21:43:08 +01001044 WCMD_execute (firstcmd, (*cmdList)->redirects, variable, value, cmdList);
Francois Gouget0c01b712009-06-15 10:59:45 +02001045 HeapFree(GetProcessHeap(), 0, command);
Jason Edmeades54d890c2007-06-15 20:59:28 +01001046 }
1047
1048
Francois Gougeta3317a52007-07-05 16:10:30 +02001049 /* If it didn't move the position, step to next command */
Jason Edmeades54d890c2007-06-15 20:59:28 +01001050 if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
1051
1052 /* Process any other parts of the command */
1053 if (*cmdList) {
1054 BOOL processThese = TRUE;
1055
1056 if (isIF) processThese = conditionTRUE;
1057
1058 while (*cmdList) {
1059 const WCHAR ifElse[] = {'e','l','s','e',' ','\0'};
1060
1061 /* execute all appropriate commands */
1062 curPosition = *cmdList;
1063
Jason Edmeades84f02a62008-03-03 23:14:29 +00001064 WINE_TRACE("Processing cmdList(%p) - delim(%d) bd(%d / %d)\n",
Jason Edmeades54d890c2007-06-15 20:59:28 +01001065 *cmdList,
Jason Edmeades84f02a62008-03-03 23:14:29 +00001066 (*cmdList)->prevDelim,
Jason Edmeades54d890c2007-06-15 20:59:28 +01001067 (*cmdList)->bracketDepth, myDepth);
1068
Jason Edmeades84f02a62008-03-03 23:14:29 +00001069 /* Execute any statements appended to the line */
1070 /* FIXME: Only if previous call worked for && or failed for || */
1071 if ((*cmdList)->prevDelim == CMD_ONFAILURE ||
Dan Kegel8110dde2010-02-17 23:11:04 -08001072 (*cmdList)->prevDelim == CMD_ONSUCCESS) {
Juan Lang9c7ded02009-08-12 18:15:37 -07001073 if (processThese && (*cmdList)->command) {
Jason Edmeades1ee75382007-09-11 21:43:08 +01001074 WCMD_execute ((*cmdList)->command, (*cmdList)->redirects, variable,
1075 value, cmdList);
Jason Edmeades54d890c2007-06-15 20:59:28 +01001076 }
1077 if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
1078
1079 /* Execute any appended to the statement with (...) */
1080 } else if ((*cmdList)->bracketDepth > myDepth) {
1081 if (processThese) {
1082 *cmdList = WCMD_process_commands(*cmdList, TRUE, variable, value);
1083 WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList);
1084 }
1085 if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
1086
1087 /* End of the command - does 'ELSE ' follow as the next command? */
1088 } else {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001089 if (isIF && CompareStringW(LOCALE_USER_DEFAULT,
Jason Edmeades54d890c2007-06-15 20:59:28 +01001090 NORM_IGNORECASE | SORT_STRINGSORT,
1091 (*cmdList)->command, 5, ifElse, -1) == 2) {
1092
1093 /* Swap between if and else processing */
1094 processThese = !processThese;
1095
1096 /* Process the ELSE part */
1097 if (processThese) {
1098 WCHAR *cmd = ((*cmdList)->command) + strlenW(ifElse);
1099
1100 /* Skip leading whitespace between condition and the command */
1101 while (*cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
1102 if (*cmd) {
Jason Edmeades1ee75382007-09-11 21:43:08 +01001103 WCMD_execute (cmd, (*cmdList)->redirects, variable, value, cmdList);
Jason Edmeades54d890c2007-06-15 20:59:28 +01001104 }
1105 }
1106 if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
1107 } else {
1108 WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList);
1109 break;
1110 }
1111 }
1112 }
1113 }
1114 return;
Dave Pickles036a9f71999-07-10 11:36:45 +00001115}
1116
Dave Pickles74f440e1999-06-06 15:24:04 +00001117/**************************************************************************
1118 * WCMD_give_help
1119 *
1120 * Simple on-line help. Help text is stored in the resource file.
1121 */
1122
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001123void WCMD_give_help (WCHAR *command) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001124
Alexandre Julliardabfe1052007-03-01 12:43:19 +01001125 int i;
Dave Pickles74f440e1999-06-06 15:24:04 +00001126
1127 command = WCMD_strtrim_leading_spaces(command);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001128 if (strlenW(command) == 0) {
Jason Edmeadesafe4d802007-06-03 22:07:43 +01001129 WCMD_output_asis (WCMD_LoadMessage(WCMD_ALLHELP));
Dave Pickles74f440e1999-06-06 15:24:04 +00001130 }
1131 else {
1132 for (i=0; i<=WCMD_EXIT; i++) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001133 if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
Arjun Comara607f532010-03-02 16:26:09 -05001134 command, -1, inbuilt[i], -1) == 2) {
Jason Edmeadesafe4d802007-06-03 22:07:43 +01001135 WCMD_output_asis (WCMD_LoadMessage(i));
Dave Picklesebecf502000-08-01 22:02:18 +00001136 return;
Dave Pickles74f440e1999-06-06 15:24:04 +00001137 }
1138 }
Arjun Comara607f532010-03-02 16:26:09 -05001139 WCMD_output (WCMD_LoadMessage(WCMD_NOCMDHELP), command);
Dave Pickles74f440e1999-06-06 15:24:04 +00001140 }
1141 return;
1142}
1143
1144/****************************************************************************
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001145 * WCMD_go_to
1146 *
1147 * Batch file jump instruction. Not the most efficient algorithm ;-)
1148 * Prints error message if the specified label cannot be found - the file pointer is
1149 * then at EOF, effectively stopping the batch file.
1150 * FIXME: DOS is supposed to allow labels with spaces - we don't.
1151 */
1152
Jason Edmeades929a92f2007-06-15 20:59:22 +01001153void WCMD_goto (CMD_LIST **cmdList) {
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001154
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001155 WCHAR string[MAX_PATH];
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001156
Jason Edmeades929a92f2007-06-15 20:59:22 +01001157 /* Do not process any more parts of a processed multipart or multilines command */
Jason Edmeadesb6924112007-09-11 21:43:03 +01001158 if (cmdList) *cmdList = NULL;
Jason Edmeades929a92f2007-06-15 20:59:22 +01001159
Markus Amsler765ff5d2006-10-31 21:11:28 +01001160 if (param1[0] == 0x00) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001161 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Markus Amsler765ff5d2006-10-31 21:11:28 +01001162 return;
1163 }
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001164 if (context != NULL) {
Nikolay Sivove22f6aa2010-03-23 22:45:25 -05001165 WCHAR *paramStart = param1, *str;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001166 static const WCHAR eofW[] = {':','e','o','f','\0'};
Jason Edmeades54829242007-02-20 18:00:37 +00001167
1168 /* Handle special :EOF label */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001169 if (lstrcmpiW (eofW, param1) == 0) {
Jason Edmeades54829242007-02-20 18:00:37 +00001170 context -> skip_rest = TRUE;
1171 return;
1172 }
1173
Jason Edmeades327d7ef2007-02-23 22:19:25 +00001174 /* Support goto :label as well as goto label */
1175 if (*paramStart == ':') paramStart++;
1176
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001177 SetFilePointer (context -> h, 0, NULL, FILE_BEGIN);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001178 while (WCMD_fgets (string, sizeof(string)/sizeof(WCHAR), context -> h)) {
Nikolay Sivove22f6aa2010-03-23 22:45:25 -05001179 str = string;
1180 while (isspaceW(*str)) str++;
1181 if ((*str == ':') && (lstrcmpiW (++str, paramStart) == 0)) return;
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001182 }
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001183 WCMD_output (WCMD_LoadMessage(WCMD_NOTARGET));
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001184 }
1185 return;
1186}
1187
Jason Edmeades365f86f2007-02-23 22:17:28 +00001188/*****************************************************************************
1189 * WCMD_pushd
1190 *
1191 * Push a directory onto the stack
1192 */
1193
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001194void WCMD_pushd (WCHAR *command) {
Jason Edmeades365f86f2007-02-23 22:17:28 +00001195 struct env_stack *curdir;
Jason Edmeades365f86f2007-02-23 22:17:28 +00001196 WCHAR *thisdir;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001197 static const WCHAR parmD[] = {'/','D','\0'};
Jason Edmeades365f86f2007-02-23 22:17:28 +00001198
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001199 if (strchrW(command, '/') != NULL) {
Jason Edmeades91aa8a02007-03-08 00:44:46 +00001200 SetLastError(ERROR_INVALID_PARAMETER);
1201 WCMD_print_error();
1202 return;
1203 }
1204
Jason Edmeades365f86f2007-02-23 22:17:28 +00001205 curdir = LocalAlloc (LMEM_FIXED, sizeof (struct env_stack));
1206 thisdir = LocalAlloc (LMEM_FIXED, 1024 * sizeof(WCHAR));
1207 if( !curdir || !thisdir ) {
1208 LocalFree(curdir);
1209 LocalFree(thisdir);
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001210 WINE_ERR ("out of memory\n");
Jason Edmeades365f86f2007-02-23 22:17:28 +00001211 return;
1212 }
1213
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001214 /* Change directory using CD code with /D parameter */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001215 strcpyW(quals, parmD);
Jason Edmeades365f86f2007-02-23 22:17:28 +00001216 GetCurrentDirectoryW (1024, thisdir);
Jason Edmeadese5a26bc2007-03-08 00:44:09 +00001217 errorlevel = 0;
1218 WCMD_setshow_default(command);
1219 if (errorlevel) {
Jason Edmeades365f86f2007-02-23 22:17:28 +00001220 LocalFree(curdir);
1221 LocalFree(thisdir);
1222 return;
1223 } else {
1224 curdir -> next = pushd_directories;
1225 curdir -> strings = thisdir;
Jason Edmeades8049ae12007-03-04 22:34:20 +00001226 if (pushd_directories == NULL) {
Francois Gouget540d8182007-03-12 10:35:13 +01001227 curdir -> u.stackdepth = 1;
Jason Edmeades8049ae12007-03-04 22:34:20 +00001228 } else {
Francois Gouget540d8182007-03-12 10:35:13 +01001229 curdir -> u.stackdepth = pushd_directories -> u.stackdepth + 1;
Jason Edmeades8049ae12007-03-04 22:34:20 +00001230 }
Jason Edmeades365f86f2007-02-23 22:17:28 +00001231 pushd_directories = curdir;
1232 }
1233}
1234
1235
1236/*****************************************************************************
1237 * WCMD_popd
1238 *
1239 * Pop a directory from the stack
1240 */
1241
1242void WCMD_popd (void) {
1243 struct env_stack *temp = pushd_directories;
1244
1245 if (!pushd_directories)
1246 return;
1247
1248 /* pop the old environment from the stack, and make it the current dir */
1249 pushd_directories = temp->next;
1250 SetCurrentDirectoryW(temp->strings);
1251 LocalFree (temp->strings);
1252 LocalFree (temp);
1253}
Dave Pickles5f8f4f71999-06-26 10:24:08 +00001254
1255/****************************************************************************
Dave Pickles74f440e1999-06-06 15:24:04 +00001256 * WCMD_if
1257 *
1258 * Batch file conditional.
Jason Edmeadesd2e7b402007-06-15 20:59:27 +01001259 *
1260 * On entry, cmdlist will point to command containing the IF, and optionally
1261 * the first command to execute (if brackets not found)
1262 * If &&'s were found, this may be followed by a record flagged as isAmpersand
1263 * If ('s were found, execute all within that bracket
1264 * Command may optionally be followed by an ELSE - need to skip instructions
1265 * in the else using the same logic
1266 *
Dave Pickles036a9f71999-07-10 11:36:45 +00001267 * FIXME: Much more syntax checking needed!
Dave Pickles74f440e1999-06-06 15:24:04 +00001268 */
1269
Jason Edmeades8f12d8b2007-06-15 20:59:21 +01001270void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001271
Alexandre Julliardabfe1052007-03-01 12:43:19 +01001272 int negate = 0, test = 0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001273 WCHAR condition[MAX_PATH], *command, *s;
1274 static const WCHAR notW[] = {'n','o','t','\0'};
1275 static const WCHAR errlvlW[] = {'e','r','r','o','r','l','e','v','e','l','\0'};
1276 static const WCHAR existW[] = {'e','x','i','s','t','\0'};
1277 static const WCHAR defdW[] = {'d','e','f','i','n','e','d','\0'};
1278 static const WCHAR eqeqW[] = {'=','=','\0'};
Trey Hunnerafb374b2010-02-02 01:09:06 -08001279 static const WCHAR parmI[] = {'/','I','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00001280
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001281 if (!lstrcmpiW (param1, notW)) {
Dave Pickles036a9f71999-07-10 11:36:45 +00001282 negate = 1;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001283 strcpyW (condition, param2);
Alexandre Julliardabfe1052007-03-01 12:43:19 +01001284 }
Dave Pickles036a9f71999-07-10 11:36:45 +00001285 else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001286 strcpyW (condition, param1);
Dave Pickles036a9f71999-07-10 11:36:45 +00001287 }
Jason Edmeadesbcaf4fb2007-09-11 21:43:05 +01001288 WINE_TRACE("Condition: %s\n", wine_dbgstr_w(condition));
1289
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001290 if (!lstrcmpiW (condition, errlvlW)) {
1291 if (errorlevel >= atoiW(WCMD_parameter (p, 1+negate, NULL))) test = 1;
Alexandre Julliard36bf7922003-01-15 03:35:32 +00001292 WCMD_parameter (p, 2+negate, &command);
Dave Pickles036a9f71999-07-10 11:36:45 +00001293 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001294 else if (!lstrcmpiW (condition, existW)) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001295 if (GetFileAttributesW(WCMD_parameter (p, 1+negate, NULL)) != INVALID_FILE_ATTRIBUTES) {
Jason Edmeadesc79342a2005-02-14 11:01:35 +00001296 test = 1;
Dave Pickles036a9f71999-07-10 11:36:45 +00001297 }
Alexandre Julliard36bf7922003-01-15 03:35:32 +00001298 WCMD_parameter (p, 2+negate, &command);
Dave Pickles036a9f71999-07-10 11:36:45 +00001299 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001300 else if (!lstrcmpiW (condition, defdW)) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001301 if (GetEnvironmentVariableW(WCMD_parameter (p, 1+negate, NULL), NULL, 0) > 0) {
Jason Edmeades758a3972007-02-20 17:47:35 +00001302 test = 1;
1303 }
1304 WCMD_parameter (p, 2+negate, &command);
1305 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001306 else if ((s = strstrW (p, eqeqW))) {
Dave Pickles036a9f71999-07-10 11:36:45 +00001307 s += 2;
Trey Hunnerafb374b2010-02-02 01:09:06 -08001308 if (strstrW (quals, parmI) == NULL) {
1309 if (!lstrcmpW (condition, WCMD_parameter (s, 0, NULL))) test = 1;
1310 }
1311 else {
1312 if (!lstrcmpiW (condition, WCMD_parameter (s, 0, NULL))) test = 1;
1313 }
Alexandre Julliard36bf7922003-01-15 03:35:32 +00001314 WCMD_parameter (s, 1, &command);
Dave Pickles036a9f71999-07-10 11:36:45 +00001315 }
1316 else {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001317 WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
Dave Pickles036a9f71999-07-10 11:36:45 +00001318 return;
1319 }
Jason Edmeadesd2e7b402007-06-15 20:59:27 +01001320
1321 /* Process rest of IF statement which is on the same line
1322 Note: This may process all or some of the cmdList (eg a GOTO) */
Jason Edmeades54d890c2007-06-15 20:59:28 +01001323 WCMD_part_execute(cmdList, command, NULL, NULL, TRUE, (test != negate));
Dave Pickles74f440e1999-06-06 15:24:04 +00001324}
1325
1326/****************************************************************************
1327 * WCMD_move
1328 *
1329 * Move a file, directory tree or wildcarded set of files.
1330 */
1331
Eric Pouechb2f079b2003-02-27 01:41:21 +00001332void WCMD_move (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001333
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001334 int status;
Alexandre Julliard79b00722009-12-09 18:52:40 +01001335 WIN32_FIND_DATAW fd;
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001336 HANDLE hff;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001337 WCHAR input[MAX_PATH];
1338 WCHAR output[MAX_PATH];
1339 WCHAR drive[10];
1340 WCHAR dir[MAX_PATH];
1341 WCHAR fname[MAX_PATH];
1342 WCHAR ext[MAX_PATH];
Dave Pickles036a9f71999-07-10 11:36:45 +00001343
Markus Amsler765ff5d2006-10-31 21:11:28 +01001344 if (param1[0] == 0x00) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001345 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Markus Amsler765ff5d2006-10-31 21:11:28 +01001346 return;
1347 }
1348
Jason Edmeades13c51172002-04-20 20:54:38 +00001349 /* If no destination supplied, assume current directory */
1350 if (param2[0] == 0x00) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001351 strcpyW(param2, dotW);
Jason Edmeades13c51172002-04-20 20:54:38 +00001352 }
1353
1354 /* If 2nd parm is directory, then use original filename */
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001355 /* Convert partial path to full path */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001356 GetFullPathNameW(param1, sizeof(input)/sizeof(WCHAR), input, NULL);
1357 GetFullPathNameW(param2, sizeof(output)/sizeof(WCHAR), output, NULL);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001358 WINE_TRACE("Move from '%s'('%s') to '%s'\n", wine_dbgstr_w(input),
1359 wine_dbgstr_w(param1), wine_dbgstr_w(output));
Jason Edmeades13c51172002-04-20 20:54:38 +00001360
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001361 /* Split into components */
1362 WCMD_splitpath(input, drive, dir, fname, ext);
1363
Alexandre Julliard79b00722009-12-09 18:52:40 +01001364 hff = FindFirstFileW(input, &fd);
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001365 while (hff != INVALID_HANDLE_VALUE) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001366 WCHAR dest[MAX_PATH];
1367 WCHAR src[MAX_PATH];
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001368 DWORD attribs;
1369
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001370 WINE_TRACE("Processing file '%s'\n", wine_dbgstr_w(fd.cFileName));
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001371
1372 /* Build src & dest name */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001373 strcpyW(src, drive);
1374 strcatW(src, dir);
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001375
1376 /* See if dest is an existing directory */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001377 attribs = GetFileAttributesW(output);
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001378 if (attribs != INVALID_FILE_ATTRIBUTES &&
1379 (attribs & FILE_ATTRIBUTE_DIRECTORY)) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001380 strcpyW(dest, output);
1381 strcatW(dest, slashW);
1382 strcatW(dest, fd.cFileName);
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001383 } else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001384 strcpyW(dest, output);
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001385 }
1386
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001387 strcatW(src, fd.cFileName);
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001388
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001389 WINE_TRACE("Source '%s'\n", wine_dbgstr_w(src));
1390 WINE_TRACE("Dest '%s'\n", wine_dbgstr_w(dest));
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001391
1392 /* Check if file is read only, otherwise move it */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001393 attribs = GetFileAttributesW(src);
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001394 if ((attribs != INVALID_FILE_ATTRIBUTES) &&
1395 (attribs & FILE_ATTRIBUTE_READONLY)) {
1396 SetLastError(ERROR_ACCESS_DENIED);
1397 status = 0;
1398 } else {
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001399 BOOL ok = TRUE;
1400
1401 /* If destination exists, prompt unless /Y supplied */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001402 if (GetFileAttributesW(dest) != INVALID_FILE_ATTRIBUTES) {
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001403 BOOL force = FALSE;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001404 WCHAR copycmd[MAXSTRING];
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001405 int len;
1406
1407 /* /-Y has the highest priority, then /Y and finally the COPYCMD env. variable */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001408 if (strstrW (quals, parmNoY))
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001409 force = FALSE;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001410 else if (strstrW (quals, parmY))
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001411 force = TRUE;
1412 else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001413 const WCHAR copyCmdW[] = {'C','O','P','Y','C','M','D','\0'};
Alexandre Julliard79b00722009-12-09 18:52:40 +01001414 len = GetEnvironmentVariableW(copyCmdW, copycmd, sizeof(copycmd)/sizeof(WCHAR));
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001415 force = (len && len < (sizeof(copycmd)/sizeof(WCHAR))
1416 && ! lstrcmpiW (copycmd, parmY));
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001417 }
1418
1419 /* Prompt if overwriting */
1420 if (!force) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001421 WCHAR question[MAXSTRING];
1422 WCHAR yesChar[10];
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001423
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001424 strcpyW(yesChar, WCMD_LoadMessage(WCMD_YES));
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001425
1426 /* Ask for confirmation */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001427 wsprintfW(question, WCMD_LoadMessage(WCMD_OVERWRITE), dest);
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001428 ok = WCMD_ask_confirm(question, FALSE, NULL);
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001429
1430 /* So delete the destination prior to the move */
1431 if (ok) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001432 if (!DeleteFileW(dest)) {
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001433 WCMD_print_error ();
1434 errorlevel = 1;
1435 ok = FALSE;
1436 }
1437 }
1438 }
1439 }
1440
1441 if (ok) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001442 status = MoveFileW(src, dest);
Jason Edmeades2f5bfc02007-04-11 22:25:53 +01001443 } else {
1444 status = 1; /* Anything other than 0 to prevent error msg below */
1445 }
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001446 }
1447
1448 if (!status) {
1449 WCMD_print_error ();
1450 errorlevel = 1;
1451 }
1452
1453 /* Step on to next match */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001454 if (FindNextFileW(hff, &fd) == 0) {
Jason Edmeadesd0a6fe12007-04-11 22:25:52 +01001455 FindClose(hff);
1456 hff = INVALID_HANDLE_VALUE;
1457 break;
1458 }
1459 }
Dave Pickles74f440e1999-06-06 15:24:04 +00001460}
1461
1462/****************************************************************************
1463 * WCMD_pause
1464 *
1465 * Wait for keyboard input.
1466 */
1467
Eric Pouechb2f079b2003-02-27 01:41:21 +00001468void WCMD_pause (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001469
Alexandre Julliardabfe1052007-03-01 12:43:19 +01001470 DWORD count;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001471 WCHAR string[32];
Dave Pickles74f440e1999-06-06 15:24:04 +00001472
1473 WCMD_output (anykey);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001474 WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE), string,
1475 sizeof(string)/sizeof(WCHAR), &count, NULL);
Dave Pickles74f440e1999-06-06 15:24:04 +00001476}
1477
1478/****************************************************************************
1479 * WCMD_remove_dir
1480 *
1481 * Delete a directory.
1482 */
1483
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001484void WCMD_remove_dir (WCHAR *command) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001485
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001486 int argno = 0;
1487 int argsProcessed = 0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001488 WCHAR *argN = command;
1489 static const WCHAR parmS[] = {'/','S','\0'};
1490 static const WCHAR parmQ[] = {'/','Q','\0'};
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001491
1492 /* Loop through all args */
1493 while (argN) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001494 WCHAR *thisArg = WCMD_parameter (command, argno++, &argN);
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001495 if (argN && argN[0] != '/') {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001496 WINE_TRACE("rd: Processing arg %s (quals:%s)\n", wine_dbgstr_w(thisArg),
1497 wine_dbgstr_w(quals));
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001498 argsProcessed++;
1499
1500 /* If subdirectory search not supplied, just try to remove
1501 and report error if it fails (eg if it contains a file) */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001502 if (strstrW (quals, parmS) == NULL) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001503 if (!RemoveDirectoryW(thisArg)) WCMD_print_error ();
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001504
1505 /* Otherwise use ShFileOp to recursively remove a directory */
1506 } else {
1507
Alexandre Julliard79b00722009-12-09 18:52:40 +01001508 SHFILEOPSTRUCTW lpDir;
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001509
1510 /* Ask first */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001511 if (strstrW (quals, parmQ) == NULL) {
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001512 BOOL ok;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001513 WCHAR question[MAXSTRING];
1514 static const WCHAR fmt[] = {'%','s',' ','\0'};
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001515
1516 /* Ask for confirmation */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001517 wsprintfW(question, fmt, thisArg);
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001518 ok = WCMD_ask_confirm(question, TRUE, NULL);
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001519
1520 /* Abort if answer is 'N' */
1521 if (!ok) return;
1522 }
1523
1524 /* Do the delete */
1525 lpDir.hwnd = NULL;
1526 lpDir.pTo = NULL;
1527 lpDir.pFrom = thisArg;
1528 lpDir.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI;
1529 lpDir.wFunc = FO_DELETE;
Alexandre Julliard79b00722009-12-09 18:52:40 +01001530 if (SHFileOperationW(&lpDir)) WCMD_print_error ();
Jason Edmeades0efa91d2007-03-04 22:33:27 +00001531 }
1532 }
1533 }
1534
1535 /* Handle no valid args */
1536 if (argsProcessed == 0) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001537 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Markus Amsler765ff5d2006-10-31 21:11:28 +01001538 return;
1539 }
Jason Edmeades69194ce2007-02-26 23:04:40 +00001540
Dave Pickles74f440e1999-06-06 15:24:04 +00001541}
1542
1543/****************************************************************************
1544 * WCMD_rename
1545 *
1546 * Rename a file.
Dave Pickles74f440e1999-06-06 15:24:04 +00001547 */
1548
Eric Pouechb2f079b2003-02-27 01:41:21 +00001549void WCMD_rename (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001550
Jason Edmeades32fc3662007-04-11 22:25:51 +01001551 int status;
1552 HANDLE hff;
Alexandre Julliard79b00722009-12-09 18:52:40 +01001553 WIN32_FIND_DATAW fd;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001554 WCHAR input[MAX_PATH];
1555 WCHAR *dotDst = NULL;
1556 WCHAR drive[10];
1557 WCHAR dir[MAX_PATH];
1558 WCHAR fname[MAX_PATH];
1559 WCHAR ext[MAX_PATH];
Jason Edmeades32fc3662007-04-11 22:25:51 +01001560 DWORD attribs;
Dave Pickles74f440e1999-06-06 15:24:04 +00001561
Jason Edmeades32fc3662007-04-11 22:25:51 +01001562 errorlevel = 0;
1563
1564 /* Must be at least two args */
Markus Amsler765ff5d2006-10-31 21:11:28 +01001565 if (param1[0] == 0x00 || param2[0] == 0x00) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001566 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Jason Edmeades32fc3662007-04-11 22:25:51 +01001567 errorlevel = 1;
Markus Amsler765ff5d2006-10-31 21:11:28 +01001568 return;
1569 }
Jason Edmeades32fc3662007-04-11 22:25:51 +01001570
1571 /* Destination cannot contain a drive letter or directory separator */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001572 if ((strchrW(param1,':') != NULL) || (strchrW(param1,'\\') != NULL)) {
Jason Edmeades32fc3662007-04-11 22:25:51 +01001573 SetLastError(ERROR_INVALID_PARAMETER);
1574 WCMD_print_error();
1575 errorlevel = 1;
1576 return;
Dave Pickles74f440e1999-06-06 15:24:04 +00001577 }
Jason Edmeades32fc3662007-04-11 22:25:51 +01001578
1579 /* Convert partial path to full path */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001580 GetFullPathNameW(param1, sizeof(input)/sizeof(WCHAR), input, NULL);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001581 WINE_TRACE("Rename from '%s'('%s') to '%s'\n", wine_dbgstr_w(input),
1582 wine_dbgstr_w(param1), wine_dbgstr_w(param2));
1583 dotDst = strchrW(param2, '.');
Jason Edmeades32fc3662007-04-11 22:25:51 +01001584
1585 /* Split into components */
1586 WCMD_splitpath(input, drive, dir, fname, ext);
1587
Alexandre Julliard79b00722009-12-09 18:52:40 +01001588 hff = FindFirstFileW(input, &fd);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001589 while (hff != INVALID_HANDLE_VALUE) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001590 WCHAR dest[MAX_PATH];
1591 WCHAR src[MAX_PATH];
1592 WCHAR *dotSrc = NULL;
Jason Edmeades32fc3662007-04-11 22:25:51 +01001593 int dirLen;
1594
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001595 WINE_TRACE("Processing file '%s'\n", wine_dbgstr_w(fd.cFileName));
Jason Edmeades32fc3662007-04-11 22:25:51 +01001596
1597 /* FIXME: If dest name or extension is *, replace with filename/ext
1598 part otherwise use supplied name. This supports:
1599 ren *.fred *.jim
1600 ren jim.* fred.* etc
Francois Gouget4c8e2182008-02-13 22:11:01 +01001601 However, windows has a more complex algorithm supporting eg
Jason Edmeades32fc3662007-04-11 22:25:51 +01001602 ?'s and *'s mid name */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001603 dotSrc = strchrW(fd.cFileName, '.');
Jason Edmeades32fc3662007-04-11 22:25:51 +01001604
1605 /* Build src & dest name */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001606 strcpyW(src, drive);
1607 strcatW(src, dir);
1608 strcpyW(dest, src);
1609 dirLen = strlenW(src);
1610 strcatW(src, fd.cFileName);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001611
1612 /* Build name */
1613 if (param2[0] == '*') {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001614 strcatW(dest, fd.cFileName);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001615 if (dotSrc) dest[dirLen + (dotSrc - fd.cFileName)] = 0x00;
1616 } else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001617 strcatW(dest, param2);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001618 if (dotDst) dest[dirLen + (dotDst - param2)] = 0x00;
1619 }
1620
1621 /* Build Extension */
1622 if (dotDst && (*(dotDst+1)=='*')) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001623 if (dotSrc) strcatW(dest, dotSrc);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001624 } else if (dotDst) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001625 if (dotDst) strcatW(dest, dotDst);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001626 }
1627
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001628 WINE_TRACE("Source '%s'\n", wine_dbgstr_w(src));
1629 WINE_TRACE("Dest '%s'\n", wine_dbgstr_w(dest));
Jason Edmeades32fc3662007-04-11 22:25:51 +01001630
1631 /* Check if file is read only, otherwise move it */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001632 attribs = GetFileAttributesW(src);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001633 if ((attribs != INVALID_FILE_ATTRIBUTES) &&
1634 (attribs & FILE_ATTRIBUTE_READONLY)) {
1635 SetLastError(ERROR_ACCESS_DENIED);
1636 status = 0;
1637 } else {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001638 status = MoveFileW(src, dest);
Jason Edmeades32fc3662007-04-11 22:25:51 +01001639 }
1640
1641 if (!status) {
1642 WCMD_print_error ();
1643 errorlevel = 1;
1644 }
1645
1646 /* Step on to next match */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001647 if (FindNextFileW(hff, &fd) == 0) {
Jason Edmeades32fc3662007-04-11 22:25:51 +01001648 FindClose(hff);
1649 hff = INVALID_HANDLE_VALUE;
1650 break;
1651 }
1652 }
Dave Pickles74f440e1999-06-06 15:24:04 +00001653}
1654
1655/*****************************************************************************
Mike McCormack9643b792004-03-22 22:56:58 +00001656 * WCMD_dupenv
1657 *
1658 * Make a copy of the environment.
1659 */
Eric Pouech5c2a8912004-11-29 18:00:10 +00001660static WCHAR *WCMD_dupenv( const WCHAR *env )
Mike McCormack9643b792004-03-22 22:56:58 +00001661{
1662 WCHAR *env_copy;
1663 int len;
1664
1665 if( !env )
1666 return NULL;
1667
1668 len = 0;
1669 while ( env[len] )
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001670 len += (strlenW(&env[len]) + 1);
Mike McCormack9643b792004-03-22 22:56:58 +00001671
1672 env_copy = LocalAlloc (LMEM_FIXED, (len+1) * sizeof (WCHAR) );
1673 if (!env_copy)
1674 {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001675 WINE_ERR("out of memory\n");
Mike McCormack9643b792004-03-22 22:56:58 +00001676 return env_copy;
1677 }
1678 memcpy (env_copy, env, len*sizeof (WCHAR));
1679 env_copy[len] = 0;
1680
1681 return env_copy;
1682}
1683
1684/*****************************************************************************
1685 * WCMD_setlocal
1686 *
1687 * setlocal pushes the environment onto a stack
1688 * Save the environment as unicode so we don't screw anything up.
1689 */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001690void WCMD_setlocal (const WCHAR *s) {
Mike McCormack9643b792004-03-22 22:56:58 +00001691 WCHAR *env;
1692 struct env_stack *env_copy;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001693 WCHAR cwd[MAX_PATH];
Mike McCormack9643b792004-03-22 22:56:58 +00001694
1695 /* DISABLEEXTENSIONS ignored */
1696
1697 env_copy = LocalAlloc (LMEM_FIXED, sizeof (struct env_stack));
1698 if( !env_copy )
1699 {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01001700 WINE_ERR ("out of memory\n");
Mike McCormack9643b792004-03-22 22:56:58 +00001701 return;
1702 }
1703
1704 env = GetEnvironmentStringsW ();
1705
1706 env_copy->strings = WCMD_dupenv (env);
1707 if (env_copy->strings)
1708 {
1709 env_copy->next = saved_environment;
1710 saved_environment = env_copy;
Jason Edmeades86140e32007-03-08 00:48:49 +00001711
1712 /* Save the current drive letter */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001713 GetCurrentDirectoryW(MAX_PATH, cwd);
Francois Gouget540d8182007-03-12 10:35:13 +01001714 env_copy->u.cwd = cwd[0];
Mike McCormack9643b792004-03-22 22:56:58 +00001715 }
1716 else
1717 LocalFree (env_copy);
1718
1719 FreeEnvironmentStringsW (env);
Jason Edmeades86140e32007-03-08 00:48:49 +00001720
Mike McCormack9643b792004-03-22 22:56:58 +00001721}
1722
1723/*****************************************************************************
Mike McCormack9643b792004-03-22 22:56:58 +00001724 * WCMD_endlocal
1725 *
1726 * endlocal pops the environment off a stack
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001727 * Note: When searching for '=', search from WCHAR position 1, to handle
Jason Edmeades86140e32007-03-08 00:48:49 +00001728 * special internal environment variables =C:, =D: etc
Mike McCormack9643b792004-03-22 22:56:58 +00001729 */
1730void WCMD_endlocal (void) {
1731 WCHAR *env, *old, *p;
1732 struct env_stack *temp;
1733 int len, n;
1734
1735 if (!saved_environment)
1736 return;
1737
1738 /* pop the old environment from the stack */
1739 temp = saved_environment;
1740 saved_environment = temp->next;
1741
1742 /* delete the current environment, totally */
1743 env = GetEnvironmentStringsW ();
1744 old = WCMD_dupenv (GetEnvironmentStringsW ());
1745 len = 0;
1746 while (old[len]) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001747 n = strlenW(&old[len]) + 1;
1748 p = strchrW(&old[len] + 1, '=');
Mike McCormack9643b792004-03-22 22:56:58 +00001749 if (p)
1750 {
1751 *p++ = 0;
1752 SetEnvironmentVariableW (&old[len], NULL);
1753 }
1754 len += n;
1755 }
1756 LocalFree (old);
1757 FreeEnvironmentStringsW (env);
Jason Edmeadesfda72292007-02-27 23:18:57 +00001758
Mike McCormack9643b792004-03-22 22:56:58 +00001759 /* restore old environment */
1760 env = temp->strings;
1761 len = 0;
1762 while (env[len]) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001763 n = strlenW(&env[len]) + 1;
1764 p = strchrW(&env[len] + 1, '=');
Mike McCormack9643b792004-03-22 22:56:58 +00001765 if (p)
1766 {
1767 *p++ = 0;
1768 SetEnvironmentVariableW (&env[len], p);
1769 }
1770 len += n;
1771 }
Jason Edmeades86140e32007-03-08 00:48:49 +00001772
1773 /* Restore current drive letter */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001774 if (IsCharAlphaW(temp->u.cwd)) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001775 WCHAR envvar[4];
1776 WCHAR cwd[MAX_PATH];
1777 static const WCHAR fmt[] = {'=','%','c',':','\0'};
1778
Alexandre Julliard79b00722009-12-09 18:52:40 +01001779 wsprintfW(envvar, fmt, temp->u.cwd);
1780 if (GetEnvironmentVariableW(envvar, cwd, MAX_PATH)) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001781 WINE_TRACE("Resetting cwd to %s\n", wine_dbgstr_w(cwd));
Alexandre Julliard79b00722009-12-09 18:52:40 +01001782 SetCurrentDirectoryW(cwd);
Jason Edmeades86140e32007-03-08 00:48:49 +00001783 }
1784 }
1785
Mike McCormack9643b792004-03-22 22:56:58 +00001786 LocalFree (env);
1787 LocalFree (temp);
1788}
1789
1790/*****************************************************************************
Dave Pickles74f440e1999-06-06 15:24:04 +00001791 * WCMD_setshow_attrib
1792 *
1793 * Display and optionally sets DOS attributes on a file or directory
1794 *
Dave Pickles74f440e1999-06-06 15:24:04 +00001795 */
1796
Eric Pouechb2f079b2003-02-27 01:41:21 +00001797void WCMD_setshow_attrib (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001798
Alexandre Julliardabfe1052007-03-01 12:43:19 +01001799 DWORD count;
1800 HANDLE hff;
Alexandre Julliard79b00722009-12-09 18:52:40 +01001801 WIN32_FIND_DATAW fd;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001802 WCHAR flags[9] = {' ',' ',' ',' ',' ',' ',' ',' ','\0'};
Dan Kegel81e5c762009-09-24 10:52:36 -07001803 WCHAR *name = param1;
1804 DWORD attrib_set=0;
1805 DWORD attrib_clear=0;
Dave Pickles74f440e1999-06-06 15:24:04 +00001806
Dan Kegel81e5c762009-09-24 10:52:36 -07001807 if (param1[0] == '+' || param1[0] == '-') {
1808 DWORD attrib = 0;
1809 /* FIXME: the real cmd can handle many more than two args; this should be in a loop */
1810 switch (param1[1]) {
1811 case 'H': case 'h': attrib |= FILE_ATTRIBUTE_HIDDEN; break;
1812 case 'S': case 's': attrib |= FILE_ATTRIBUTE_SYSTEM; break;
1813 case 'R': case 'r': attrib |= FILE_ATTRIBUTE_READONLY; break;
1814 case 'A': case 'a': attrib |= FILE_ATTRIBUTE_ARCHIVE; break;
1815 default:
1816 WCMD_output (WCMD_LoadMessage(WCMD_NYI));
1817 return;
1818 }
1819 switch (param1[0]) {
1820 case '+': attrib_set = attrib; break;
1821 case '-': attrib_clear = attrib; break;
1822 }
1823 name = param2;
Dave Pickles036a9f71999-07-10 11:36:45 +00001824 }
1825
Dan Kegel81e5c762009-09-24 10:52:36 -07001826 if (strlenW(name) == 0) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001827 static const WCHAR slashStarW[] = {'\\','*','\0'};
1828
Alexandre Julliard79b00722009-12-09 18:52:40 +01001829 GetCurrentDirectoryW(sizeof(param2)/sizeof(WCHAR), name);
Dan Kegel81e5c762009-09-24 10:52:36 -07001830 strcatW (name, slashStarW);
Dave Pickles74f440e1999-06-06 15:24:04 +00001831 }
1832
Alexandre Julliard79b00722009-12-09 18:52:40 +01001833 hff = FindFirstFileW(name, &fd);
Dave Pickles74f440e1999-06-06 15:24:04 +00001834 if (hff == INVALID_HANDLE_VALUE) {
Dan Kegel81e5c762009-09-24 10:52:36 -07001835 WCMD_output (WCMD_LoadMessage(WCMD_FILENOTFOUND), name);
Dave Pickles74f440e1999-06-06 15:24:04 +00001836 }
1837 else {
1838 do {
Dan Kegel81e5c762009-09-24 10:52:36 -07001839 if (attrib_set || attrib_clear) {
1840 fd.dwFileAttributes &= ~attrib_clear;
1841 fd.dwFileAttributes |= attrib_set;
1842 if (!fd.dwFileAttributes)
1843 fd.dwFileAttributes |= FILE_ATTRIBUTE_NORMAL;
1844 SetFileAttributesW(name, fd.dwFileAttributes);
1845 } else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001846 static const WCHAR fmt[] = {'%','s',' ',' ',' ','%','s','\n','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00001847 if (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
1848 flags[0] = 'H';
1849 }
1850 if (fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
1851 flags[1] = 'S';
1852 }
1853 if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
1854 flags[2] = 'A';
1855 }
1856 if (fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
1857 flags[3] = 'R';
1858 }
1859 if (fd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
1860 flags[4] = 'T';
1861 }
1862 if (fd.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
1863 flags[5] = 'C';
1864 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001865 WCMD_output (fmt, flags, fd.cFileName);
Dave Pickles74f440e1999-06-06 15:24:04 +00001866 for (count=0; count < 8; count++) flags[count] = ' ';
1867 }
Alexandre Julliard79b00722009-12-09 18:52:40 +01001868 } while (FindNextFileW(hff, &fd) != 0);
Dave Pickles74f440e1999-06-06 15:24:04 +00001869 }
1870 FindClose (hff);
1871}
1872
1873/*****************************************************************************
1874 * WCMD_setshow_default
1875 *
1876 * Set/Show the current default directory
1877 */
1878
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001879void WCMD_setshow_default (WCHAR *command) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001880
Alexandre Julliardabfe1052007-03-01 12:43:19 +01001881 BOOL status;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001882 WCHAR string[1024];
1883 WCHAR cwd[1024];
1884 WCHAR *pos;
Alexandre Julliard79b00722009-12-09 18:52:40 +01001885 WIN32_FIND_DATAW fd;
Jason Edmeades5c8c6942007-03-08 00:43:09 +00001886 HANDLE hff;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001887 static const WCHAR parmD[] = {'/','D','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00001888
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001889 WINE_TRACE("Request change to directory '%s'\n", wine_dbgstr_w(command));
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001890
1891 /* Skip /D and trailing whitespace if on the front of the command line */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001892 if (CompareStringW(LOCALE_USER_DEFAULT,
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001893 NORM_IGNORECASE | SORT_STRINGSORT,
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001894 command, 2, parmD, -1) == 2) {
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001895 command += 2;
1896 while (*command && *command==' ') command++;
1897 }
1898
Alexandre Julliard79b00722009-12-09 18:52:40 +01001899 GetCurrentDirectoryW(sizeof(cwd)/sizeof(WCHAR), cwd);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001900 if (strlenW(command) == 0) {
1901 strcatW (cwd, newline);
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001902 WCMD_output (cwd);
Dave Pickles74f440e1999-06-06 15:24:04 +00001903 }
1904 else {
Jason Edmeadeseb6d0842007-03-08 00:42:33 +00001905 /* Remove any double quotes, which may be in the
1906 middle, eg. cd "C:\Program Files"\Microsoft is ok */
1907 pos = string;
1908 while (*command) {
1909 if (*command != '"') *pos++ = *command;
1910 command++;
1911 }
1912 *pos = 0x00;
1913
Francois Gouget8a18e0e2008-04-07 13:01:02 +02001914 /* Search for appropriate directory */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001915 WINE_TRACE("Looking for directory '%s'\n", wine_dbgstr_w(string));
Alexandre Julliard79b00722009-12-09 18:52:40 +01001916 hff = FindFirstFileW(string, &fd);
Jason Edmeades5c8c6942007-03-08 00:43:09 +00001917 while (hff != INVALID_HANDLE_VALUE) {
1918 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001919 WCHAR fpath[MAX_PATH];
1920 WCHAR drive[10];
1921 WCHAR dir[MAX_PATH];
1922 WCHAR fname[MAX_PATH];
1923 WCHAR ext[MAX_PATH];
1924 static const WCHAR fmt[] = {'%','s','%','s','%','s','\0'};
Jason Edmeades5c8c6942007-03-08 00:43:09 +00001925
1926 /* Convert path into actual directory spec */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001927 GetFullPathNameW(string, sizeof(fpath)/sizeof(WCHAR), fpath, NULL);
Jason Edmeades5c8c6942007-03-08 00:43:09 +00001928 WCMD_splitpath(fpath, drive, dir, fname, ext);
1929
1930 /* Rebuild path */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001931 wsprintfW(string, fmt, drive, dir, fd.cFileName);
Jason Edmeades5c8c6942007-03-08 00:43:09 +00001932
1933 FindClose(hff);
1934 hff = INVALID_HANDLE_VALUE;
1935 break;
1936 }
1937
1938 /* Step on to next match */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001939 if (FindNextFileW(hff, &fd) == 0) {
Jason Edmeades5c8c6942007-03-08 00:43:09 +00001940 FindClose(hff);
1941 hff = INVALID_HANDLE_VALUE;
1942 break;
1943 }
1944 }
1945
Jason Edmeadeseb6d0842007-03-08 00:42:33 +00001946 /* Change to that directory */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001947 WINE_TRACE("Really changing to directory '%s'\n", wine_dbgstr_w(string));
Jason Edmeades2b03d7d2007-03-08 00:47:45 +00001948
Alexandre Julliard79b00722009-12-09 18:52:40 +01001949 status = SetCurrentDirectoryW(string);
Dave Pickles74f440e1999-06-06 15:24:04 +00001950 if (!status) {
Jason Edmeades121a8302007-03-08 00:43:32 +00001951 errorlevel = 1;
Dave Pickles74f440e1999-06-06 15:24:04 +00001952 WCMD_print_error ();
1953 return;
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001954 } else {
1955
Jason Edmeades44923342008-03-03 23:14:30 +00001956 /* Save away the actual new directory, to store as current location */
1957 GetCurrentDirectoryW (sizeof(string)/sizeof(WCHAR), string);
1958
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001959 /* Restore old directory if drive letter would change, and
1960 CD x:\directory /D (or pushd c:\directory) not supplied */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001961 if ((strstrW(quals, parmD) == NULL) &&
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001962 (param1[1] == ':') && (toupper(param1[0]) != toupper(cwd[0]))) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001963 SetCurrentDirectoryW(cwd);
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001964 }
Dave Pickles74f440e1999-06-06 15:24:04 +00001965 }
Jason Edmeades2b03d7d2007-03-08 00:47:45 +00001966
Jason Edmeadesffbaede2007-03-08 00:50:14 +00001967 /* Set special =C: type environment variable, for drive letter of
1968 change of directory, even if path was restored due to missing
1969 /D (allows changing drive letter when not resident on that
1970 drive */
Alexandre Julliard79b00722009-12-09 18:52:40 +01001971 if ((string[1] == ':') && IsCharAlphaW(string[0])) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001972 WCHAR env[4];
1973 strcpyW(env, equalW);
1974 memcpy(env+1, string, 2 * sizeof(WCHAR));
Jason Edmeades2b03d7d2007-03-08 00:47:45 +00001975 env[3] = 0x00;
Alexandre Julliardabc5fef2007-06-08 12:54:21 +02001976 WINE_TRACE("Setting '%s' to '%s'\n", wine_dbgstr_w(env), wine_dbgstr_w(string));
Alexandre Julliard79b00722009-12-09 18:52:40 +01001977 SetEnvironmentVariableW(env, string);
Jason Edmeades2b03d7d2007-03-08 00:47:45 +00001978 }
1979
Dave Pickles74f440e1999-06-06 15:24:04 +00001980 }
1981 return;
1982}
1983
1984/****************************************************************************
1985 * WCMD_setshow_date
1986 *
1987 * Set/Show the system date
1988 * FIXME: Can't change date yet
1989 */
1990
Eric Pouechb2f079b2003-02-27 01:41:21 +00001991void WCMD_setshow_date (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00001992
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001993 WCHAR curdate[64], buffer[64];
Alexandre Julliardabfe1052007-03-01 12:43:19 +01001994 DWORD count;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001995 static const WCHAR parmT[] = {'/','T','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00001996
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001997 if (strlenW(param1) == 0) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01001998 if (GetDateFormatW(LOCALE_USER_DEFAULT, 0, NULL, NULL,
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01001999 curdate, sizeof(curdate)/sizeof(WCHAR))) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002000 WCMD_output (WCMD_LoadMessage(WCMD_CURRENTDATE), curdate);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002001 if (strstrW (quals, parmT) == NULL) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002002 WCMD_output (WCMD_LoadMessage(WCMD_NEWDATE));
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002003 WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE),
2004 buffer, sizeof(buffer)/sizeof(WCHAR), &count, NULL);
Jason Edmeades988ef412007-03-08 00:45:05 +00002005 if (count > 2) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002006 WCMD_output (WCMD_LoadMessage(WCMD_NYI));
Jason Edmeades988ef412007-03-08 00:45:05 +00002007 }
Dave Pickles74f440e1999-06-06 15:24:04 +00002008 }
2009 }
2010 else WCMD_print_error ();
2011 }
2012 else {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002013 WCMD_output (WCMD_LoadMessage(WCMD_NYI));
Dave Pickles74f440e1999-06-06 15:24:04 +00002014 }
2015}
2016
2017/****************************************************************************
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002018 * WCMD_compare
2019 */
Eric Pouech5c2a8912004-11-29 18:00:10 +00002020static int WCMD_compare( const void *a, const void *b )
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002021{
2022 int r;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002023 const WCHAR * const *str_a = a, * const *str_b = b;
Alexandre Julliard79b00722009-12-09 18:52:40 +01002024 r = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002025 *str_a, -1, *str_b, -1 );
2026 if( r == CSTR_LESS_THAN ) return -1;
2027 if( r == CSTR_GREATER_THAN ) return 1;
2028 return 0;
2029}
2030
2031/****************************************************************************
2032 * WCMD_setshow_sortenv
2033 *
2034 * sort variables into order for display
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002035 * Optionally only display those who start with a stub
2036 * returns the count displayed
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002037 */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002038static int WCMD_setshow_sortenv(const WCHAR *s, const WCHAR *stub)
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002039{
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002040 UINT count=0, len=0, i, displayedcount=0, stublen=0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002041 const WCHAR **str;
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002042
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002043 if (stub) stublen = strlenW(stub);
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002044
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002045 /* count the number of strings, and the total length */
2046 while ( s[len] ) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002047 len += (strlenW(&s[len]) + 1);
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002048 count++;
2049 }
2050
2051 /* add the strings to an array */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002052 str = LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, count * sizeof (WCHAR*) );
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002053 if( !str )
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002054 return 0;
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002055 str[0] = s;
2056 for( i=1; i<count; i++ )
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002057 str[i] = str[i-1] + strlenW(str[i-1]) + 1;
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002058
2059 /* sort the array */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002060 qsort( str, count, sizeof (WCHAR*), WCMD_compare );
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002061
2062 /* print it */
Rein Klazesa18ea3d2005-12-01 15:58:16 +01002063 for( i=0; i<count; i++ ) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002064 if (!stub || CompareStringW(LOCALE_USER_DEFAULT,
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002065 NORM_IGNORECASE | SORT_STRINGSORT,
2066 str[i], stublen, stub, -1) == 2) {
Jason Edmeadesd1317f52007-03-08 00:48:17 +00002067 /* Don't display special internal variables */
2068 if (str[i][0] != '=') {
2069 WCMD_output_asis(str[i]);
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002070 WCMD_output_asis(newline);
Jason Edmeadesd1317f52007-03-08 00:48:17 +00002071 displayedcount++;
2072 }
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002073 }
Rein Klazesa18ea3d2005-12-01 15:58:16 +01002074 }
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002075
2076 LocalFree( str );
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002077 return displayedcount;
Mike McCormackbbe0e2c2003-12-30 19:17:31 +00002078}
2079
2080/****************************************************************************
Dave Pickles74f440e1999-06-06 15:24:04 +00002081 * WCMD_setshow_env
2082 *
2083 * Set/Show the environment variables
Dave Pickles74f440e1999-06-06 15:24:04 +00002084 */
2085
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002086void WCMD_setshow_env (WCHAR *s) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002087
Alexandre Julliardabfe1052007-03-01 12:43:19 +01002088 LPVOID env;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002089 WCHAR *p;
Alexandre Julliardabfe1052007-03-01 12:43:19 +01002090 int status;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002091 static const WCHAR parmP[] = {'/','P','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00002092
Jason Edmeades87f02932007-03-13 00:11:31 +00002093 errorlevel = 0;
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002094 if (param1[0] == 0x00 && quals[0] == 0x00) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002095 env = GetEnvironmentStringsW();
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002096 WCMD_setshow_sortenv( env, NULL );
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002097 return;
Dave Pickles74f440e1999-06-06 15:24:04 +00002098 }
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002099
2100 /* See if /P supplied, and if so echo the prompt, and read in a reply */
Alexandre Julliard79b00722009-12-09 18:52:40 +01002101 if (CompareStringW(LOCALE_USER_DEFAULT,
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002102 NORM_IGNORECASE | SORT_STRINGSORT,
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002103 s, 2, parmP, -1) == 2) {
2104 WCHAR string[MAXSTRING];
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002105 DWORD count;
2106
2107 s += 2;
2108 while (*s && *s==' ') s++;
André Hentschel765d9a12009-08-28 18:34:32 +02002109 if (*s=='\"')
2110 WCMD_opt_s_strip_quotes(s);
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002111
2112 /* If no parameter, or no '=' sign, return an error */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002113 if (!(*s) || ((p = strchrW (s, '=')) == NULL )) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002114 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002115 return;
2116 }
2117
2118 /* Output the prompt */
2119 *p++ = '\0';
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002120 if (strlenW(p) != 0) WCMD_output(p);
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002121
2122 /* Read the reply */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002123 WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE), string,
2124 sizeof(string)/sizeof(WCHAR), &count, NULL);
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002125 if (count > 1) {
2126 string[count-1] = '\0'; /* ReadFile output is not null-terminated! */
2127 if (string[count-2] == '\r') string[count-2] = '\0'; /* Under Windoze we get CRLF! */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002128 WINE_TRACE("set /p: Setting var '%s' to '%s'\n", wine_dbgstr_w(s),
2129 wine_dbgstr_w(string));
Alexandre Julliard79b00722009-12-09 18:52:40 +01002130 status = SetEnvironmentVariableW(s, string);
Jason Edmeades4b1ef912007-03-13 00:11:04 +00002131 }
2132
2133 } else {
Jason Edmeades87f02932007-03-13 00:11:31 +00002134 DWORD gle;
André Hentschel765d9a12009-08-28 18:34:32 +02002135
2136 if (*s=='\"')
2137 WCMD_opt_s_strip_quotes(s);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002138 p = strchrW (s, '=');
Dave Pickles74f440e1999-06-06 15:24:04 +00002139 if (p == NULL) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002140 env = GetEnvironmentStringsW();
Jason Edmeades1c632cd2007-02-26 23:06:11 +00002141 if (WCMD_setshow_sortenv( env, s ) == 0) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002142 WCMD_output (WCMD_LoadMessage(WCMD_MISSINGENV), s);
Jason Edmeades87f02932007-03-13 00:11:31 +00002143 errorlevel = 1;
Vincent Béron9a624912002-05-31 23:06:46 +00002144 }
Dave Pickles74f440e1999-06-06 15:24:04 +00002145 return;
2146 }
2147 *p++ = '\0';
Jason Edmeadesa5910f42000-08-01 02:14:33 +00002148
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002149 if (strlenW(p) == 0) p = NULL;
Alexandre Julliard79b00722009-12-09 18:52:40 +01002150 status = SetEnvironmentVariableW(s, p);
Jason Edmeades87f02932007-03-13 00:11:31 +00002151 gle = GetLastError();
2152 if ((!status) & (gle == ERROR_ENVVAR_NOT_FOUND)) {
2153 errorlevel = 1;
2154 } else if ((!status)) WCMD_print_error();
Dave Pickles74f440e1999-06-06 15:24:04 +00002155 }
Dave Pickles74f440e1999-06-06 15:24:04 +00002156}
2157
2158/****************************************************************************
2159 * WCMD_setshow_path
2160 *
2161 * Set/Show the path environment variable
2162 */
2163
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002164void WCMD_setshow_path (WCHAR *command) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002165
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002166 WCHAR string[1024];
Alexandre Julliardabfe1052007-03-01 12:43:19 +01002167 DWORD status;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002168 static const WCHAR pathW[] = {'P','A','T','H','\0'};
2169 static const WCHAR pathEqW[] = {'P','A','T','H','=','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00002170
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002171 if (strlenW(param1) == 0) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002172 status = GetEnvironmentVariableW(pathW, string, sizeof(string)/sizeof(WCHAR));
Dave Pickles74f440e1999-06-06 15:24:04 +00002173 if (status != 0) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002174 WCMD_output_asis ( pathEqW);
Rein Klazes0bf64a42005-12-02 11:25:51 +01002175 WCMD_output_asis ( string);
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002176 WCMD_output_asis ( newline);
Dave Pickles74f440e1999-06-06 15:24:04 +00002177 }
2178 else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002179 WCMD_output (WCMD_LoadMessage(WCMD_NOPATH));
Dave Pickles74f440e1999-06-06 15:24:04 +00002180 }
2181 }
2182 else {
Jason Edmeades73587982007-02-20 00:37:47 +00002183 if (*command == '=') command++; /* Skip leading '=' */
Alexandre Julliard79b00722009-12-09 18:52:40 +01002184 status = SetEnvironmentVariableW(pathW, command);
Dave Pickles74f440e1999-06-06 15:24:04 +00002185 if (!status) WCMD_print_error();
2186 }
2187}
2188
2189/****************************************************************************
2190 * WCMD_setshow_prompt
2191 *
2192 * Set or show the command prompt.
2193 */
2194
Eric Pouechb2f079b2003-02-27 01:41:21 +00002195void WCMD_setshow_prompt (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002196
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002197 WCHAR *s;
2198 static const WCHAR promptW[] = {'P','R','O','M','P','T','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00002199
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002200 if (strlenW(param1) == 0) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002201 SetEnvironmentVariableW(promptW, NULL);
Dave Pickles74f440e1999-06-06 15:24:04 +00002202 }
2203 else {
2204 s = param1;
2205 while ((*s == '=') || (*s == ' ')) s++;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002206 if (strlenW(s) == 0) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002207 SetEnvironmentVariableW(promptW, NULL);
Dave Pickles74f440e1999-06-06 15:24:04 +00002208 }
Alexandre Julliard79b00722009-12-09 18:52:40 +01002209 else SetEnvironmentVariableW(promptW, s);
Dave Pickles74f440e1999-06-06 15:24:04 +00002210 }
2211}
2212
2213/****************************************************************************
2214 * WCMD_setshow_time
2215 *
2216 * Set/Show the system time
2217 * FIXME: Can't change time yet
2218 */
2219
Eric Pouechb2f079b2003-02-27 01:41:21 +00002220void WCMD_setshow_time (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002221
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002222 WCHAR curtime[64], buffer[64];
Alexandre Julliardabfe1052007-03-01 12:43:19 +01002223 DWORD count;
2224 SYSTEMTIME st;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002225 static const WCHAR parmT[] = {'/','T','\0'};
Dave Pickles74f440e1999-06-06 15:24:04 +00002226
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002227 if (strlenW(param1) == 0) {
Dave Pickles036a9f71999-07-10 11:36:45 +00002228 GetLocalTime(&st);
Alexandre Julliard79b00722009-12-09 18:52:40 +01002229 if (GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL,
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002230 curtime, sizeof(curtime)/sizeof(WCHAR))) {
Christian Costa656b6272008-12-30 13:26:53 +01002231 WCMD_output (WCMD_LoadMessage(WCMD_CURRENTTIME), curtime);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002232 if (strstrW (quals, parmT) == NULL) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002233 WCMD_output (WCMD_LoadMessage(WCMD_NEWTIME));
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002234 WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE), buffer,
2235 sizeof(buffer)/sizeof(WCHAR), &count, NULL);
Jason Edmeadesb6ed73b2007-03-08 00:45:27 +00002236 if (count > 2) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002237 WCMD_output (WCMD_LoadMessage(WCMD_NYI));
Jason Edmeadesb6ed73b2007-03-08 00:45:27 +00002238 }
Dave Pickles74f440e1999-06-06 15:24:04 +00002239 }
2240 }
2241 else WCMD_print_error ();
2242 }
2243 else {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002244 WCMD_output (WCMD_LoadMessage(WCMD_NYI));
Dave Pickles74f440e1999-06-06 15:24:04 +00002245 }
2246}
2247
2248/****************************************************************************
2249 * WCMD_shift
2250 *
2251 * Shift batch parameters.
Jason Edmeades612dc9d2007-03-08 00:50:37 +00002252 * Optional /n says where to start shifting (n=0-8)
Dave Pickles74f440e1999-06-06 15:24:04 +00002253 */
2254
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002255void WCMD_shift (WCHAR *command) {
Jason Edmeades612dc9d2007-03-08 00:50:37 +00002256 int start;
Dave Pickles74f440e1999-06-06 15:24:04 +00002257
Jason Edmeades612dc9d2007-03-08 00:50:37 +00002258 if (context != NULL) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002259 WCHAR *pos = strchrW(command, '/');
Jason Edmeades612dc9d2007-03-08 00:50:37 +00002260 int i;
2261
2262 if (pos == NULL) {
2263 start = 0;
2264 } else if (*(pos+1)>='0' && *(pos+1)<='8') {
2265 start = (*(pos+1) - '0');
2266 } else {
2267 SetLastError(ERROR_INVALID_PARAMETER);
2268 WCMD_print_error();
2269 return;
2270 }
2271
2272 WINE_TRACE("Shifting variables, starting at %d\n", start);
2273 for (i=start;i<=8;i++) {
2274 context -> shift_count[i] = context -> shift_count[i+1] + 1;
2275 }
2276 context -> shift_count[9] = context -> shift_count[9] + 1;
2277 }
Dave Pickles74f440e1999-06-06 15:24:04 +00002278
2279}
2280
2281/****************************************************************************
Jason Edmeadesbcc62562002-05-04 18:29:31 +00002282 * WCMD_title
2283 *
2284 * Set the console title
2285 */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002286void WCMD_title (WCHAR *command) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002287 SetConsoleTitleW(command);
Jason Edmeadesbcc62562002-05-04 18:29:31 +00002288}
2289
2290/****************************************************************************
Dave Pickles74f440e1999-06-06 15:24:04 +00002291 * WCMD_type
2292 *
2293 * Copy a file to standard output.
2294 */
2295
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002296void WCMD_type (WCHAR *command) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002297
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002298 int argno = 0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002299 WCHAR *argN = command;
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002300 BOOL writeHeaders = FALSE;
Dave Pickles74f440e1999-06-06 15:24:04 +00002301
Markus Amsler765ff5d2006-10-31 21:11:28 +01002302 if (param1[0] == 0x00) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002303 WCMD_output (WCMD_LoadMessage(WCMD_NOARG));
Markus Amsler765ff5d2006-10-31 21:11:28 +01002304 return;
2305 }
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002306
2307 if (param2[0] != 0x00) writeHeaders = TRUE;
2308
2309 /* Loop through all args */
2310 errorlevel = 0;
2311 while (argN) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002312 WCHAR *thisArg = WCMD_parameter (command, argno++, &argN);
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002313
2314 HANDLE h;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002315 WCHAR buffer[512];
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002316 DWORD count;
2317
2318 if (!argN) break;
2319
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002320 WINE_TRACE("type: Processing arg '%s'\n", wine_dbgstr_w(thisArg));
Alexandre Julliard79b00722009-12-09 18:52:40 +01002321 h = CreateFileW(thisArg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002322 FILE_ATTRIBUTE_NORMAL, NULL);
2323 if (h == INVALID_HANDLE_VALUE) {
2324 WCMD_print_error ();
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002325 WCMD_output (WCMD_LoadMessage(WCMD_READFAIL), thisArg);
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002326 errorlevel = 1;
2327 } else {
2328 if (writeHeaders) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002329 static const WCHAR fmt[] = {'\n','%','s','\n','\n','\0'};
2330 WCMD_output(fmt, thisArg);
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002331 }
Nikolay Sivov2dd1b3b2009-02-17 22:45:21 +03002332 while (WCMD_ReadFile (h, buffer, sizeof(buffer)/sizeof(WCHAR) - 1, &count, NULL)) {
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002333 if (count == 0) break; /* ReadFile reports success on EOF! */
2334 buffer[count] = 0;
2335 WCMD_output_asis (buffer);
2336 }
2337 CloseHandle (h);
Nikolay Sivov78f38a72009-02-17 22:39:42 +03002338 if (!writeHeaders)
2339 WCMD_output_asis (newline);
Jason Edmeades4ef2f8b2007-03-13 00:09:33 +00002340 }
Dave Pickles74f440e1999-06-06 15:24:04 +00002341 }
Dave Pickles74f440e1999-06-06 15:24:04 +00002342}
2343
2344/****************************************************************************
Jason Edmeadesce875222007-04-13 21:34:05 +01002345 * WCMD_more
2346 *
2347 * Output either a file or stdin to screen in pages
2348 */
2349
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002350void WCMD_more (WCHAR *command) {
Jason Edmeadesce875222007-04-13 21:34:05 +01002351
2352 int argno = 0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002353 WCHAR *argN = command;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002354 WCHAR moreStr[100];
2355 WCHAR moreStrPage[100];
2356 WCHAR buffer[512];
Jason Edmeadesce875222007-04-13 21:34:05 +01002357 DWORD count;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002358 static const WCHAR moreStart[] = {'-','-',' ','\0'};
2359 static const WCHAR moreFmt[] = {'%','s',' ','-','-','\n','\0'};
2360 static const WCHAR moreFmt2[] = {'%','s',' ','(','%','2','.','2','d','%','%',
2361 ')',' ','-','-','\n','\0'};
2362 static const WCHAR conInW[] = {'C','O','N','I','N','$','\0'};
Jason Edmeadesce875222007-04-13 21:34:05 +01002363
2364 /* Prefix the NLS more with '-- ', then load the text */
2365 errorlevel = 0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002366 strcpyW(moreStr, moreStart);
Alexandre Julliard79b00722009-12-09 18:52:40 +01002367 LoadStringW(hinst, WCMD_MORESTR, &moreStr[3],
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002368 (sizeof(moreStr)/sizeof(WCHAR))-3);
Jason Edmeadesce875222007-04-13 21:34:05 +01002369
2370 if (param1[0] == 0x00) {
2371
2372 /* Wine implements pipes via temporary files, and hence stdin is
2373 effectively reading from the file. This means the prompts for
Francois Gouget8a18e0e2008-04-07 13:01:02 +02002374 more are satisfied by the next line from the input (file). To
Jason Edmeadesce875222007-04-13 21:34:05 +01002375 avoid this, ensure stdin is to the console */
2376 HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
Alexandre Julliard79b00722009-12-09 18:52:40 +01002377 HANDLE hConIn = CreateFileW(conInW, GENERIC_READ | GENERIC_WRITE,
Jason Edmeadesce875222007-04-13 21:34:05 +01002378 FILE_SHARE_READ, NULL, OPEN_EXISTING,
2379 FILE_ATTRIBUTE_NORMAL, 0);
Jason Edmeades84f02a62008-03-03 23:14:29 +00002380 WINE_TRACE("No parms - working probably in pipe mode\n");
Jason Edmeadesce875222007-04-13 21:34:05 +01002381 SetStdHandle(STD_INPUT_HANDLE, hConIn);
2382
2383 /* Warning: No easy way of ending the stream (ctrl+z on windows) so
2384 once you get in this bit unless due to a pipe, its going to end badly... */
Alexandre Julliard79b00722009-12-09 18:52:40 +01002385 wsprintfW(moreStrPage, moreFmt, moreStr);
Jason Edmeadesce875222007-04-13 21:34:05 +01002386
2387 WCMD_enter_paged_mode(moreStrPage);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002388 while (WCMD_ReadFile (hstdin, buffer, (sizeof(buffer)/sizeof(WCHAR))-1, &count, NULL)) {
Jason Edmeadesce875222007-04-13 21:34:05 +01002389 if (count == 0) break; /* ReadFile reports success on EOF! */
2390 buffer[count] = 0;
2391 WCMD_output_asis (buffer);
2392 }
2393 WCMD_leave_paged_mode();
2394
2395 /* Restore stdin to what it was */
2396 SetStdHandle(STD_INPUT_HANDLE, hstdin);
2397 CloseHandle(hConIn);
2398
2399 return;
2400 } else {
2401 BOOL needsPause = FALSE;
2402
2403 /* Loop through all args */
Jason Edmeades84f02a62008-03-03 23:14:29 +00002404 WINE_TRACE("Parms supplied - working through each file\n");
Jason Edmeadesce875222007-04-13 21:34:05 +01002405 WCMD_enter_paged_mode(moreStrPage);
2406
2407 while (argN) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002408 WCHAR *thisArg = WCMD_parameter (command, argno++, &argN);
Jason Edmeadesce875222007-04-13 21:34:05 +01002409 HANDLE h;
2410
2411 if (!argN) break;
2412
2413 if (needsPause) {
2414
2415 /* Wait */
Alexandre Julliard79b00722009-12-09 18:52:40 +01002416 wsprintfW(moreStrPage, moreFmt2, moreStr, 100);
Jason Edmeadesce875222007-04-13 21:34:05 +01002417 WCMD_leave_paged_mode();
2418 WCMD_output_asis(moreStrPage);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002419 WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE), buffer,
2420 sizeof(buffer)/sizeof(WCHAR), &count, NULL);
Jason Edmeadesce875222007-04-13 21:34:05 +01002421 WCMD_enter_paged_mode(moreStrPage);
2422 }
2423
2424
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002425 WINE_TRACE("more: Processing arg '%s'\n", wine_dbgstr_w(thisArg));
Alexandre Julliard79b00722009-12-09 18:52:40 +01002426 h = CreateFileW(thisArg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
Jason Edmeadesce875222007-04-13 21:34:05 +01002427 FILE_ATTRIBUTE_NORMAL, NULL);
2428 if (h == INVALID_HANDLE_VALUE) {
2429 WCMD_print_error ();
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002430 WCMD_output (WCMD_LoadMessage(WCMD_READFAIL), thisArg);
Jason Edmeadesce875222007-04-13 21:34:05 +01002431 errorlevel = 1;
2432 } else {
2433 ULONG64 curPos = 0;
2434 ULONG64 fileLen = 0;
2435 WIN32_FILE_ATTRIBUTE_DATA fileInfo;
2436
2437 /* Get the file size */
Alexandre Julliard79b00722009-12-09 18:52:40 +01002438 GetFileAttributesExW(thisArg, GetFileExInfoStandard, (void*)&fileInfo);
Jason Edmeadesce875222007-04-13 21:34:05 +01002439 fileLen = (((ULONG64)fileInfo.nFileSizeHigh) << 32) + fileInfo.nFileSizeLow;
2440
2441 needsPause = TRUE;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002442 while (WCMD_ReadFile (h, buffer, (sizeof(buffer)/sizeof(WCHAR))-1, &count, NULL)) {
Jason Edmeadesce875222007-04-13 21:34:05 +01002443 if (count == 0) break; /* ReadFile reports success on EOF! */
2444 buffer[count] = 0;
2445 curPos += count;
2446
2447 /* Update % count (would be used in WCMD_output_asis as prompt) */
Alexandre Julliard79b00722009-12-09 18:52:40 +01002448 wsprintfW(moreStrPage, moreFmt2, moreStr, (int) min(99, (curPos * 100)/fileLen));
Jason Edmeadesce875222007-04-13 21:34:05 +01002449
2450 WCMD_output_asis (buffer);
2451 }
2452 CloseHandle (h);
2453 }
2454 }
2455
2456 WCMD_leave_paged_mode();
2457 }
2458}
2459
2460/****************************************************************************
Dave Pickles74f440e1999-06-06 15:24:04 +00002461 * WCMD_verify
2462 *
2463 * Display verify flag.
Dave Pickles5f8f4f71999-06-26 10:24:08 +00002464 * FIXME: We don't actually do anything with the verify flag other than toggle
2465 * it...
Dave Pickles74f440e1999-06-06 15:24:04 +00002466 */
2467
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002468void WCMD_verify (WCHAR *command) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002469
Alexandre Julliardabfe1052007-03-01 12:43:19 +01002470 int count;
Dave Pickles74f440e1999-06-06 15:24:04 +00002471
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002472 count = strlenW(command);
Dave Pickles5f8f4f71999-06-26 10:24:08 +00002473 if (count == 0) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002474 if (verify_mode) WCMD_output (WCMD_LoadMessage(WCMD_VERIFYPROMPT), onW);
2475 else WCMD_output (WCMD_LoadMessage(WCMD_VERIFYPROMPT), offW);
Dave Pickles5f8f4f71999-06-26 10:24:08 +00002476 return;
2477 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002478 if (lstrcmpiW(command, onW) == 0) {
Dave Pickles5f8f4f71999-06-26 10:24:08 +00002479 verify_mode = 1;
2480 return;
2481 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002482 else if (lstrcmpiW(command, offW) == 0) {
Dave Pickles5f8f4f71999-06-26 10:24:08 +00002483 verify_mode = 0;
2484 return;
2485 }
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002486 else WCMD_output (WCMD_LoadMessage(WCMD_VERIFYERR));
Dave Pickles74f440e1999-06-06 15:24:04 +00002487}
2488
2489/****************************************************************************
2490 * WCMD_version
2491 *
2492 * Display version info.
2493 */
2494
Eric Pouechb2f079b2003-02-27 01:41:21 +00002495void WCMD_version (void) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002496
2497 WCMD_output (version_string);
2498
2499}
2500
2501/****************************************************************************
2502 * WCMD_volume
2503 *
2504 * Display volume info and/or set volume label. Returns 0 if error.
2505 */
2506
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002507int WCMD_volume (int mode, WCHAR *path) {
Dave Pickles74f440e1999-06-06 15:24:04 +00002508
Alexandre Julliardabfe1052007-03-01 12:43:19 +01002509 DWORD count, serial;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002510 WCHAR string[MAX_PATH], label[MAX_PATH], curdir[MAX_PATH];
Alexandre Julliardabfe1052007-03-01 12:43:19 +01002511 BOOL status;
Dave Pickles74f440e1999-06-06 15:24:04 +00002512
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002513 if (strlenW(path) == 0) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002514 status = GetCurrentDirectoryW(sizeof(curdir)/sizeof(WCHAR), curdir);
Dave Pickles74f440e1999-06-06 15:24:04 +00002515 if (!status) {
2516 WCMD_print_error ();
2517 return 0;
2518 }
Alexandre Julliard79b00722009-12-09 18:52:40 +01002519 status = GetVolumeInformationW(NULL, label, sizeof(label)/sizeof(WCHAR),
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002520 &serial, NULL, NULL, NULL, 0);
Dave Pickles74f440e1999-06-06 15:24:04 +00002521 }
2522 else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002523 static const WCHAR fmt[] = {'%','s','\\','\0'};
2524 if ((path[1] != ':') || (strlenW(path) != 2)) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002525 WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
Dave Pickles74f440e1999-06-06 15:24:04 +00002526 return 0;
2527 }
Alexandre Julliard79b00722009-12-09 18:52:40 +01002528 wsprintfW (curdir, fmt, path);
2529 status = GetVolumeInformationW(curdir, label, sizeof(label)/sizeof(WCHAR),
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002530 &serial, NULL,
Dave Pickles74f440e1999-06-06 15:24:04 +00002531 NULL, NULL, 0);
2532 }
2533 if (!status) {
2534 WCMD_print_error ();
2535 return 0;
2536 }
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002537 WCMD_output (WCMD_LoadMessage(WCMD_VOLUMEDETAIL),
Dave Pickles74f440e1999-06-06 15:24:04 +00002538 curdir[0], label, HIWORD(serial), LOWORD(serial));
2539 if (mode) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002540 WCMD_output (WCMD_LoadMessage(WCMD_VOLUMEPROMPT));
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002541 WCMD_ReadFile (GetStdHandle(STD_INPUT_HANDLE), string,
2542 sizeof(string)/sizeof(WCHAR), &count, NULL);
Dave Pickles036a9f71999-07-10 11:36:45 +00002543 if (count > 1) {
2544 string[count-1] = '\0'; /* ReadFile output is not null-terminated! */
2545 if (string[count-2] == '\r') string[count-2] = '\0'; /* Under Windoze we get CRLF! */
2546 }
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002547 if (strlenW(path) != 0) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002548 if (!SetVolumeLabelW(curdir, string)) WCMD_print_error ();
Dave Pickles74f440e1999-06-06 15:24:04 +00002549 }
2550 else {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002551 if (!SetVolumeLabelW(NULL, string)) WCMD_print_error ();
Dave Pickles74f440e1999-06-06 15:24:04 +00002552 }
2553 }
2554 return 1;
2555}
Jason Edmeadesc3666482007-02-20 17:49:08 +00002556
2557/**************************************************************************
2558 * WCMD_exit
2559 *
2560 * Exit either the process, or just this batch program
2561 *
2562 */
2563
Jason Edmeadesd2474de2007-06-15 20:59:24 +01002564void WCMD_exit (CMD_LIST **cmdList) {
Jason Edmeadesc3666482007-02-20 17:49:08 +00002565
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002566 static const WCHAR parmB[] = {'/','B','\0'};
2567 int rc = atoiW(param1); /* Note: atoi of empty parameter is 0 */
Jason Edmeadesc3666482007-02-20 17:49:08 +00002568
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002569 if (context && lstrcmpiW(quals, parmB) == 0) {
Jason Edmeadesc3666482007-02-20 17:49:08 +00002570 errorlevel = rc;
2571 context -> skip_rest = TRUE;
Jason Edmeadesd2474de2007-06-15 20:59:24 +01002572 *cmdList = NULL;
Jason Edmeadesc3666482007-02-20 17:49:08 +00002573 } else {
2574 ExitProcess(rc);
2575 }
2576}
Jason Edmeadesfda72292007-02-27 23:18:57 +00002577
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002578
2579/*****************************************************************************
2580 * WCMD_assoc
2581 *
Jason Edmeades9e041c62007-03-13 00:06:58 +00002582 * Lists or sets file associations (assoc = TRUE)
2583 * Lists or sets file types (assoc = FALSE)
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002584 */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002585void WCMD_assoc (WCHAR *command, BOOL assoc) {
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002586
2587 HKEY key;
2588 DWORD accessOptions = KEY_READ;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002589 WCHAR *newValue;
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002590 LONG rc = ERROR_SUCCESS;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002591 WCHAR keyValue[MAXSTRING];
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002592 DWORD valueLen = MAXSTRING;
2593 HKEY readKey;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002594 static const WCHAR shOpCmdW[] = {'\\','S','h','e','l','l','\\',
2595 'O','p','e','n','\\','C','o','m','m','a','n','d','\0'};
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002596
2597 /* See if parameter includes '=' */
2598 errorlevel = 0;
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002599 newValue = strchrW(command, '=');
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002600 if (newValue) accessOptions |= KEY_WRITE;
2601
2602 /* Open a key to HKEY_CLASSES_ROOT for enumerating */
Alexandre Julliard79b00722009-12-09 18:52:40 +01002603 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, nullW, 0,
2604 accessOptions, &key) != ERROR_SUCCESS) {
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002605 WINE_FIXME("Unexpected failure opening HKCR key: %d\n", GetLastError());
2606 return;
2607 }
2608
Francois Gouget7b0cde82007-03-06 14:26:24 +01002609 /* If no parameters then list all associations */
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002610 if (*command == 0x00) {
2611 int index = 0;
2612
2613 /* Enumerate all the keys */
2614 while (rc != ERROR_NO_MORE_ITEMS) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002615 WCHAR keyName[MAXSTRING];
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002616 DWORD nameLen;
2617
2618 /* Find the next value */
2619 nameLen = MAXSTRING;
Alexandre Julliard79b00722009-12-09 18:52:40 +01002620 rc = RegEnumKeyExW(key, index++, keyName, &nameLen, NULL, NULL, NULL, NULL);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002621
2622 if (rc == ERROR_SUCCESS) {
2623
Jason Edmeades9e041c62007-03-13 00:06:58 +00002624 /* Only interested in extension ones if assoc, or others
2625 if not assoc */
2626 if ((keyName[0] == '.' && assoc) ||
2627 (!(keyName[0] == '.') && (!assoc)))
2628 {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002629 WCHAR subkey[MAXSTRING];
2630 strcpyW(subkey, keyName);
2631 if (!assoc) strcatW(subkey, shOpCmdW);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002632
Alexandre Julliard79b00722009-12-09 18:52:40 +01002633 if (RegOpenKeyExW(key, subkey, 0, accessOptions, &readKey) == ERROR_SUCCESS) {
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002634
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002635 valueLen = sizeof(keyValue)/sizeof(WCHAR);
Alexandre Julliard79b00722009-12-09 18:52:40 +01002636 rc = RegQueryValueExW(readKey, NULL, NULL, NULL, (LPBYTE)keyValue, &valueLen);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002637 WCMD_output_asis(keyName);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002638 WCMD_output_asis(equalW);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002639 /* If no default value found, leave line empty after '=' */
2640 if (rc == ERROR_SUCCESS) {
2641 WCMD_output_asis(keyValue);
2642 }
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002643 WCMD_output_asis(newline);
Lance Jacksond56217e2008-01-03 18:03:44 -06002644 RegCloseKey(readKey);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002645 }
2646 }
2647 }
2648 }
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002649
2650 } else {
2651
2652 /* Parameter supplied - if no '=' on command line, its a query */
2653 if (newValue == NULL) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002654 WCHAR *space;
2655 WCHAR subkey[MAXSTRING];
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002656
2657 /* Query terminates the parameter at the first space */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002658 strcpyW(keyValue, command);
2659 space = strchrW(keyValue, ' ');
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002660 if (space) *space=0x00;
2661
Jason Edmeades9e041c62007-03-13 00:06:58 +00002662 /* Set up key name */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002663 strcpyW(subkey, keyValue);
2664 if (!assoc) strcatW(subkey, shOpCmdW);
Jason Edmeades9e041c62007-03-13 00:06:58 +00002665
Alexandre Julliard79b00722009-12-09 18:52:40 +01002666 if (RegOpenKeyExW(key, subkey, 0, accessOptions, &readKey) == ERROR_SUCCESS) {
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002667
Alexandre Julliard79b00722009-12-09 18:52:40 +01002668 rc = RegQueryValueExW(readKey, NULL, NULL, NULL, (LPBYTE)keyValue, &valueLen);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002669 WCMD_output_asis(command);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002670 WCMD_output_asis(equalW);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002671 /* If no default value found, leave line empty after '=' */
2672 if (rc == ERROR_SUCCESS) WCMD_output_asis(keyValue);
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002673 WCMD_output_asis(newline);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002674 RegCloseKey(readKey);
2675
2676 } else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002677 WCHAR msgbuffer[MAXSTRING];
2678 WCHAR outbuffer[MAXSTRING];
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002679
2680 /* Load the translated 'File association not found' */
Jason Edmeades9e041c62007-03-13 00:06:58 +00002681 if (assoc) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002682 LoadStringW(hinst, WCMD_NOASSOC, msgbuffer, sizeof(msgbuffer)/sizeof(WCHAR));
Jason Edmeades9e041c62007-03-13 00:06:58 +00002683 } else {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002684 LoadStringW(hinst, WCMD_NOFTYPE, msgbuffer, sizeof(msgbuffer)/sizeof(WCHAR));
Jason Edmeades9e041c62007-03-13 00:06:58 +00002685 }
Alexandre Julliard79b00722009-12-09 18:52:40 +01002686 wsprintfW(outbuffer, msgbuffer, keyValue);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002687 WCMD_output_asis(outbuffer);
2688 errorlevel = 2;
2689 }
2690
2691 /* Not a query - its a set or clear of a value */
2692 } else {
2693
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002694 WCHAR subkey[MAXSTRING];
Jason Edmeades9e041c62007-03-13 00:06:58 +00002695
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002696 /* Get pointer to new value */
2697 *newValue = 0x00;
2698 newValue++;
2699
Jason Edmeades9e041c62007-03-13 00:06:58 +00002700 /* Set up key name */
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002701 strcpyW(subkey, command);
2702 if (!assoc) strcatW(subkey, shOpCmdW);
Jason Edmeades9e041c62007-03-13 00:06:58 +00002703
2704 /* If nothing after '=' then clear value - only valid for ASSOC */
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002705 if (*newValue == 0x00) {
2706
Alexandre Julliard79b00722009-12-09 18:52:40 +01002707 if (assoc) rc = RegDeleteKeyW(key, command);
Jason Edmeades9e041c62007-03-13 00:06:58 +00002708 if (assoc && rc == ERROR_SUCCESS) {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002709 WINE_TRACE("HKCR Key '%s' deleted\n", wine_dbgstr_w(command));
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002710
Jason Edmeades9e041c62007-03-13 00:06:58 +00002711 } else if (assoc && rc != ERROR_FILE_NOT_FOUND) {
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002712 WCMD_print_error();
2713 errorlevel = 2;
2714
2715 } else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002716 WCHAR msgbuffer[MAXSTRING];
2717 WCHAR outbuffer[MAXSTRING];
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002718
2719 /* Load the translated 'File association not found' */
Jason Edmeades9e041c62007-03-13 00:06:58 +00002720 if (assoc) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002721 LoadStringW(hinst, WCMD_NOASSOC, msgbuffer,
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002722 sizeof(msgbuffer)/sizeof(WCHAR));
Jason Edmeades9e041c62007-03-13 00:06:58 +00002723 } else {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002724 LoadStringW(hinst, WCMD_NOFTYPE, msgbuffer,
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002725 sizeof(msgbuffer)/sizeof(WCHAR));
Jason Edmeades9e041c62007-03-13 00:06:58 +00002726 }
Alexandre Julliard79b00722009-12-09 18:52:40 +01002727 wsprintfW(outbuffer, msgbuffer, keyValue);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002728 WCMD_output_asis(outbuffer);
2729 errorlevel = 2;
2730 }
2731
2732 /* It really is a set value = contents */
2733 } else {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002734 rc = RegCreateKeyExW(key, subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002735 accessOptions, NULL, &readKey, NULL);
2736 if (rc == ERROR_SUCCESS) {
Alexandre Julliard79b00722009-12-09 18:52:40 +01002737 rc = RegSetValueExW(readKey, NULL, 0, REG_SZ,
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002738 (LPBYTE)newValue, strlenW(newValue));
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002739 RegCloseKey(readKey);
2740 }
2741
2742 if (rc != ERROR_SUCCESS) {
2743 WCMD_print_error();
2744 errorlevel = 2;
2745 } else {
2746 WCMD_output_asis(command);
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002747 WCMD_output_asis(equalW);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002748 WCMD_output_asis(newValue);
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002749 WCMD_output_asis(newline);
Jason Edmeades79aa1a02007-03-04 22:34:45 +00002750 }
2751 }
2752 }
2753 }
2754
2755 /* Clean up */
2756 RegCloseKey(key);
2757}
Jason Edmeadese37463f2007-03-08 00:37:44 +00002758
2759/****************************************************************************
2760 * WCMD_color
2761 *
2762 * Clear the terminal screen.
2763 */
2764
2765void WCMD_color (void) {
2766
2767 /* Emulate by filling the screen from the top left to bottom right with
2768 spaces, then moving the cursor to the top left afterwards */
2769 CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
2770 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
2771
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002772 if (param1[0] != 0x00 && strlenW(param1) > 2) {
Jason Edmeades5cc492c2007-06-03 22:07:39 +01002773 WCMD_output (WCMD_LoadMessage(WCMD_ARGERR));
Jason Edmeadese37463f2007-03-08 00:37:44 +00002774 return;
2775 }
2776
2777 if (GetConsoleScreenBufferInfo(hStdOut, &consoleInfo))
2778 {
2779 COORD topLeft;
2780 DWORD screenSize;
2781 DWORD color = 0;
2782
2783 screenSize = consoleInfo.dwSize.X * (consoleInfo.dwSize.Y + 1);
2784
2785 topLeft.X = 0;
2786 topLeft.Y = 0;
2787
2788 /* Convert the color hex digits */
2789 if (param1[0] == 0x00) {
2790 color = defaultColor;
2791 } else {
Jason Edmeadesb8aa5fc2007-06-03 22:07:42 +01002792 color = strtoulW(param1, NULL, 16);
Jason Edmeadese37463f2007-03-08 00:37:44 +00002793 }
2794
2795 /* Fail if fg == bg color */
2796 if (((color & 0xF0) >> 4) == (color & 0x0F)) {
2797 errorlevel = 1;
2798 return;
2799 }
2800
2801 /* Set the current screen contents and ensure all future writes
2802 remain this color */
2803 FillConsoleOutputAttribute(hStdOut, color, screenSize, topLeft, &screenSize);
2804 SetConsoleTextAttribute(hStdOut, color);
2805 }
2806}