Fixed out-by-one error in previous commit.
[AROS.git] / workbench / c / Rename.c
blobb6ff5ed60d16e541e40f8cedb1c92f1c2e74e3e2
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Rename CLI command.
6 */
8 /*****************************************************************************
10 NAME
12 Rename
14 SYNOPSIS
16 Rename [{FROM}] <name> [TO|AS] <name> [QUIET]
18 FROM/A/M,TO=AS/A,QUIET/S
20 LOCATION
24 FUNCTION
26 Renames a directory or file. Rename can also act like the UNIX mv
27 command, which moves a file or files to another location on disk.
29 INPUTS
31 FROM -- The name(s) of the file(s) to rename or move. There may
32 be many files specified, this is used when moving files
33 into a new directory.
35 TO|AS -- The name which we wish to call the file.
37 QUIET -- Suppress any output from the command.
39 RESULT
41 Standard DOS error codes.
43 NOTES
45 EXAMPLE
47 Rename letter1.doc letter2.doc letters
49 Moves letter1.doc and letter2.doc to the directory letters.
51 Rename ram:a ram:b quiet
52 Rename from ram:a to ram:b quiet
53 Rename from=ram:a to=ram:b quiet
55 All versions, renames file "a" to "b" and does not output any
56 diagnostic information.
58 BUGS
60 SEE ALSO
62 INTERNALS
64 Rename() can only move a file to another directory, if and only if
65 the to path has the from filename appended to the end.
67 e.g.
68 Rename("ram:a", "ram:clipboards/a");
69 not
70 Rename("ram:a", "ram:clipboards/");
72 ******************************************************************************/
74 #define DEBUG 0
75 #include <aros/debug.h>
77 #include <proto/dos.h>
78 #include <proto/exec.h>
80 #include <dos/dos.h>
81 #include <dos/dosasl.h>
82 #include <dos/rdargs.h>
83 #include <exec/memory.h>
84 #include <exec/types.h>
86 #include <string.h>
88 #define ARG_TEMPLATE "FROM/A/M,TO=AS/A,QUIET/S"
90 #define APPNAME "Rename"
92 enum
94 ARG_FROM,
95 ARG_TO,
96 ARG_QUIET,
97 NOOFARGS
101 #define MAX_PATH_LEN 2048
103 const TEXT version[] = "$VER: Rename 41.2 (23.11.2000)\n";
106 int doRename(STRPTR *from, STRPTR to, BOOL quiet);
109 int __nocommandline;
111 int main(void)
113 struct RDArgs *rda;
115 IPTR args[NOOFARGS] = { (IPTR) NULL, (IPTR) NULL, FALSE };
117 int retval = RETURN_FAIL;
119 rda = ReadArgs(ARG_TEMPLATE, args, NULL);
121 if(rda != NULL)
123 STRPTR *from = (STRPTR *)args[ARG_FROM];
124 STRPTR to = (STRPTR)args[ARG_TO];
125 BOOL quiet = args[ARG_QUIET] != 0;
127 retval = doRename(from, to, quiet);
129 FreeArgs(rda);
131 else
133 PrintFault(IoErr(), APPNAME);
134 retval = RETURN_ERROR;
137 return retval;
141 int doRename(STRPTR *from, STRPTR to, BOOL quiet)
143 #define ERROR(n) retval = (n); goto cleanup
145 struct AnchorPath *ap;
147 UBYTE *pathName;
148 STRPTR fileStart;
149 BOOL destIsDir = FALSE;
150 LONG match;
151 BPTR tolock = BNULL;
152 ULONG i;
153 int retval;
154 LONG ioerr = 0;
155 UBYTE itsWild;
156 BOOL isSingle;
158 ap = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + MAX_PATH_LEN + MAX_PATH_LEN,
159 MEMF_ANY | MEMF_CLEAR);
160 if (!ap)
162 ioerr = IoErr();
163 ERROR(RETURN_FAIL);
166 pathName = ((UBYTE *) (ap + 1)) + MAX_PATH_LEN;
168 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
169 ap->ap_Flags = APF_DOWILD;
170 ap->ap_Strlen = MAX_PATH_LEN;
171 if (MatchFirst(from[0], ap) != 0)
173 ioerr = IoErr();
174 if (ioerr == ERROR_OBJECT_NOT_FOUND)
176 Printf("Can't rename %s as %s because ", from[0], to);
178 ERROR(RETURN_FAIL);
180 itsWild = ap->ap_Flags & APF_ITSWILD;
181 MatchEnd(ap);
183 /* First we check if the destination is a directory */
184 tolock = Lock(to, SHARED_LOCK);
185 if (tolock)
187 struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
188 LONG entrytype;
190 if (!fib)
192 PrintFault(IoErr(), APPNAME);
194 ERROR(RETURN_FAIL);
197 i = Examine(tolock, fib);
198 entrytype = fib->fib_EntryType;
199 FreeDosObject(DOS_FIB, fib);
201 if (i)
203 if (entrytype >= 0)
205 destIsDir = TRUE;
208 else
210 PrintFault(IoErr(), APPNAME);
212 ERROR(RETURN_FAIL);
217 /* Check if dest is not a dir and src is pattern or multi */
218 if (!destIsDir && (itsWild || from[1]))
220 Printf("Destination \"%s\" is not a directory.\n", to);
221 ERROR(RETURN_FAIL);
225 /* Handle single file name change */
226 isSingle =!destIsDir;
227 /* 15th Jan 2004 bugfix, (destIsDir && ...) not (!destisDir && ...) ! - Piru */
228 if (destIsDir && !from[1])
230 BPTR fromlock;
232 fromlock = Lock(from[0], ACCESS_READ);
233 if (fromlock)
235 isSingle = SameLock(fromlock, tolock) == LOCK_SAME;
237 UnLock(fromlock);
240 /* 4th May 2003 bugfix: be quiet about single object renames - Piru */
241 quiet = TRUE;
243 if (isSingle)
245 if (ParsePattern(from[0], pathName, MAX_PATH_LEN) > -1 &&
246 Rename(pathName, to))
248 ERROR(RETURN_OK);
251 ioerr = IoErr();
252 Printf("Can't rename %s as %s because ", from[0], to);
253 ERROR(RETURN_FAIL);
256 if (tolock)
258 if (!NameFromLock(tolock, pathName, MAX_PATH_LEN))
260 if (IoErr() == ERROR_LINE_TOO_LONG)
262 PrintFault(IoErr(), APPNAME);
264 ERROR(RETURN_FAIL);
267 pathName[0] = '\0';
271 if (!pathName[0])
273 stccpy(pathName, to, MAX_PATH_LEN);
277 /* Now either only one specific file should be renamed or the
278 destination is really a directory. We can use the same routine
279 for both cases! */
281 fileStart = pathName + strlen(pathName);
283 ap->ap_BreakBits = SIGBREAKF_CTRL_C;
284 ap->ap_Strlen = MAX_PATH_LEN;
286 for (i = 0; from[i]; i++)
288 for (match = MatchFirst(from[i], ap); match == 0; match = MatchNext(ap))
290 /* Check for identical 'from' and 'to'? */
292 if (destIsDir)
294 /* Clear former filename */
295 *fileStart = '\0';
296 if (!AddPart(pathName, FilePart(ap->ap_Buf), MAX_PATH_LEN))
298 MatchEnd(ap);
300 PrintFault(ERROR_LINE_TOO_LONG, APPNAME);
301 SetIoErr(ERROR_LINE_TOO_LONG);
303 ERROR(RETURN_FAIL);
307 if (!quiet)
309 Printf("Renaming %s as %s\n", ap->ap_Buf, pathName);
312 if (!Rename(ap->ap_Buf, pathName))
314 ioerr = IoErr();
315 MatchEnd(ap);
317 Printf("Can't rename %s as %s because ", ap->ap_Buf, pathName);
318 ERROR(RETURN_FAIL);
322 MatchEnd(ap);
325 if (ap->ap_FoundBreak & SIGBREAKF_CTRL_C)
327 PrintFault(ERROR_BREAK, NULL);
329 retval = RETURN_WARN;
331 else
333 retval = RETURN_OK;
336 cleanup:
337 if (tolock)
339 UnLock(tolock);
342 if (ioerr)
344 //MatchEnd(ap);
345 PrintFault(ioerr, NULL);
346 SetIoErr(ioerr);
347 //retval = ERROR_FAIL;
350 FreeVec(ap);
352 return retval;