update for HEAD-2003050101
[reactos.git] / subsys / system / cmd / ren.c
1 /*
2  *  REN.C - rename internal command.
3  *
4  *
5  *  History:
6  *
7  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
8  *        added config.h include
9  *
10  *    18-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>
11  *        Added support for quoted long file names with spaces.
12  *
13  *    20-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>
14  *        Unicode and redirection safe!
15  *
16  *    17-Oct-2001 (Eric Kohl <ekohl@rz.online.de>
17  *        Implemented basic rename code.
18  */
19
20 #include "config.h"
21
22 #ifdef INCLUDE_CMD_RENAME
23
24 #include <windows.h>
25 #include <tchar.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "cmd.h"
30 #include "batch.h"
31
32 enum
33 {
34   REN_ATTRIBUTES = 0x001,   /* /A : not implemented */
35   REN_ERROR      = 0x002,   /* /E */
36   REN_NOTHING    = 0x004,   /* /N */
37   REN_PROMPT     = 0x008,   /* /P : not implemented */
38   REN_QUIET      = 0x010,   /* /Q */
39   REN_SUBDIR     = 0x020,   /* /S */
40   REN_TOTAL      = 0x040,   /* /T */
41 };
42
43
44 /*
45  *  file rename internal command.
46  *
47  */
48 INT cmd_rename (LPTSTR cmd, LPTSTR param)
49 {
50   LPTSTR *arg = NULL;
51   INT args = 0;
52   INT nEvalArgs = 0; /* nunber of evaluated arguments */
53   DWORD dwFlags = 0;
54   DWORD dwFiles = 0; /* number of renamedd files */
55   INT i;
56   LPTSTR srcPattern = NULL;
57   LPTSTR dstPattern = NULL;
58   TCHAR dstFile[MAX_PATH];
59   BOOL bDstWildcard = FALSE;
60
61   LPTSTR p,q,r;
62
63   HANDLE hFile;
64   WIN32_FIND_DATA f;
65
66   if (!_tcsncmp(param, _T("/?"), 2))
67     {
68       ConOutPuts(_T("Renames a file/directory or files/directories.\n"
69                     "\n"
70                     "RENAME [/E /N /P /Q /S /T] old_name ... new_name\n"
71                     "REN [/E /N /P /Q /S /T] old_name ... new_name\n"
72                     "\n"
73                     "  /E    No eror messages.\n"
74                     "  /N    Nothing.\n"
75                     "  /P    Prompts for confirmation before renaming each file.\n"
76                     "        (Not implemented yet!)\n"
77                     "  /Q    Quiet.\n"
78                     "  /S    Rename subdirectories.\n"
79                     "  /T    Display total number of renamed files.\n"
80                     "\n"
81                     "Note that you cannot specify a new drive or path for your destination. Use\n"
82                     "the MOVE command for that purpose."));
83       return(0);
84     }
85
86   /* split the argument list */
87   arg = split(param, &args, FALSE);
88
89   if (args < 2)
90     {
91       if (!(dwFlags & REN_ERROR))
92         error_req_param_missing();
93       freep(arg);
94       return(1);
95     }
96
97   /* read options */
98   for (i = 0; i < args; i++)
99     {
100       if (*arg[i] == _T('/'))
101         {
102           if (_tcslen(arg[i]) >= 2)
103             {
104               switch (_totupper(arg[i][1]))
105                 {
106                   case _T('E'):
107                     dwFlags |= REN_ERROR;
108                     break;
109
110                   case _T('N'):
111                     dwFlags |= REN_NOTHING;
112                     break;
113
114                   case _T('P'):
115                     dwFlags |= REN_PROMPT;
116                     break;
117
118                   case _T('Q'):
119                     dwFlags |= REN_QUIET;
120                     break;
121
122                   case _T('S'):
123                     dwFlags |= REN_SUBDIR;
124                     break;
125
126                   case _T('T'):
127                     dwFlags |= REN_TOTAL;
128                     break;
129                 }
130             }
131           nEvalArgs++;
132         }
133     }
134
135   /* keep quiet within batch files */
136   if (bc != NULL)
137     dwFlags |= REN_QUIET;
138
139   /* there are only options on the command line --> error!!! */
140   if (args < nEvalArgs + 2)
141     {
142       if (!(dwFlags & REN_ERROR))
143         error_req_param_missing();
144       freep(arg);
145       return(1);
146     }
147
148   /* get destination pattern */
149   for (i = 0; i < args; i++)
150     {
151       if (*arg[i] == _T('/'))
152         continue;
153       dstPattern = arg[i];
154     }
155
156   if (_tcschr(dstPattern, _T('*')) || _tcschr(dstPattern, _T('?')))
157     bDstWildcard = TRUE;
158
159   /* enumerate source patterns */
160   for (i = 0; i < args; i++)
161     {
162       if (*arg[i] == _T('/') || arg[i] == dstPattern)
163         continue;
164
165       srcPattern = arg[i];
166
167 #ifdef _DEBUG
168       ConErrPrintf(_T("\n\nSourcePattern: %s\n"), srcPattern);
169       ConErrPrintf(_T("DestinationPattern: %s\n"), dstPattern);
170 #endif
171
172       hFile = FindFirstFile(srcPattern, &f);
173       if (hFile == INVALID_HANDLE_VALUE)
174         {
175           if (!(dwFlags & REN_ERROR))
176             error_file_not_found();
177           continue;
178         }
179
180       do
181         {
182           /* ignore "." and ".." */
183           if (!_tcscmp (f.cFileName, _T(".")) ||
184               !_tcscmp (f.cFileName, _T("..")))
185             continue;
186
187           /* do not rename hidden or system files */
188           if (f.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
189             continue;
190
191           /* do not rename directories when the destination pattern contains
192            * wildcards, unless option /S is used */
193           if ((f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
194               && bDstWildcard
195               && !(dwFlags & REN_SUBDIR))
196             continue;
197
198 #ifdef _DEBUG
199           ConErrPrintf(_T("Found source name: %s\n"), f.cFileName);
200 #endif
201
202           /* build destination file name */
203           p = f.cFileName;
204           q = dstPattern;
205           r = dstFile;
206           while(*q != 0)
207             {
208               if (*q == '*')
209                 {
210                   q++;
211                   while (*p != 0 && *p != *q)
212                     {
213                       *r = *p;
214                       p++;
215                       r++;
216                     }
217                 }
218               else if (*q == '?')
219                 {
220                   q++;
221                   if (*p != 0)
222                     {
223                       *r = *p;
224                       p++;
225                       r++;
226                     }
227                 }
228               else
229                 {
230                   *r = *q;
231                   if (*p != 0)
232                     p++;
233                   q++;
234                   r++;
235                 }
236             }
237           *r = 0;
238
239 #ifdef _DEBUG
240           ConErrPrintf(_T("DestinationFile: %s\n"), dstFile);
241 #endif
242
243           if (!(dwFlags & REN_QUIET) && !(dwFlags & REN_TOTAL))
244             ConOutPrintf(_T("%s -> %s\n"), f.cFileName, dstFile);
245
246           /* rename the file */
247           if (!(dwFlags & REN_NOTHING))
248             {
249               if (MoveFile(f.cFileName, dstFile))
250                 {
251                   dwFiles++;
252                 }
253               else
254                 {
255                   if (!(dwFlags & REN_ERROR))
256                     ConErrPrintf(_T("MoveFile() failed. Error: %lu\n"), GetLastError());
257                 }
258             }
259         }
260       while (FindNextFile(hFile, &f));
261       FindClose(hFile);
262     }
263
264   if (!(dwFlags & REN_QUIET))
265     {
266         if (dwFiles == 1)
267           ConOutPrintf(_T("    %lu file renamed\n"),
268                        dwFiles);
269         else
270           ConOutPrintf(_T("    %lu files renamed\n"),
271                        dwFiles);
272     }
273
274   freep(arg);
275
276   return(0);
277 }
278
279 #endif
280
281 /* EOF */